77. 组合

组合问题。不需要used[]数组,限定下一次循环/搜索的起点即可.
本题不含重复数字且每个数字不可重复选择.
本题有另一种思路,即对每个数字有选与不选两种选择。
还有提前终止,时间优化很明显:

事实上,如果 n = 7, k = 4,从 55 开始搜索就已经没有意义了,这是因为:即使把 55 选上,后面的数只有 66 和 77,一共就 33 个候选数,凑不出 44 个数的组合。因此,搜索起点有上界,这个上界是多少,可以举几个例子分析。

class Solution {
    LinkedList<List<Integer>> ans=new LinkedList<>();
    LinkedList<Integer> path=new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
     dfs(1,0,n,k);
     return ans;
    }
    void dfs(int begin,int cnt,int n,int k){//k是退出递归的关键,cnt是当前数目,n是循环边界
    if(cnt==k){
        ans.add(new LinkedList(path));
        return;
    }
    for(int i=begin;i<=n;i++){
         path.add(i);
         dfs(i+1,cnt+1,n,k);//看递归退出条件,是已经收集好了以i为起点的数据/i不是第一个,但是是个起点--不要写begin+1
         path.removeLast();//找下一个起点,先把当前的删去
    }
    }
}

每个数字有选与不选两种选择:(时间和上一版本差不多)

class Solution {
    LinkedList<List<Integer>> ans=new LinkedList<>();
    LinkedList<Integer> path=new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
     dfs(1,n,k);
     return ans;
    }
    void dfs(int cur,int n,int k){//k是退出递归的关键,cnt是当前数目,n是循环边界
     if(k==0){
         ans.add(new LinkedList(path));
         return;
     }
     //递归终止,避免越界
     if(cur==n+1)return;
     dfs(cur+1,n,k);//不选当前数字

     path.add(cur);//选当前数字
     dfs(cur+1,n,k-1);
     path.removeLast();

   
    }
}

以下是升级版递归终止条件,只需要改一个判断即可,见代码

class Solution {
    LinkedList<List<Integer>> ans=new LinkedList<>();
    LinkedList<Integer> path=new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
     dfs(1,n,k);
     return ans;
    }
    void dfs(int cur,int n,int k){//k是退出递归的关键,cnt是当前数目,n是循环边界
     if(k==0){
         ans.add(new LinkedList(path));
         return;
     }
     //这里要及时判断,避免越界
     //if(cur==n+1)return;
     //以下是升级版递归终止条件
     if(cur>n-k+1)return;
     dfs(cur+1,n,k);//不选当前数字

     path.add(cur);//选当前数字
     dfs(cur+1,n,k-1);
     path.removeLast();

   
    }
}
posted @ 2021-04-24 20:18  wsshub  阅读(83)  评论(0)    收藏  举报