当前位置:   article > 正文

Leetcode 77 组合

Leetcode 77 组合

题意理解

        给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

        如:n=3,k=2,则有:12 13 23

        一般,我们使用回溯法来解决组合问题

        组合问题没有顺序要求,所以 12 21 是同一个组合(如果是排列12 21 是两种排列)

       一般我们可以把回溯法要解决的问题抽象成树结构

                集合大小=树的宽度=n        组合大小=递归深度=k

        所以

                我们可以将这个问题抽象为树问题,在递归方法中使用回溯来暴力搜索。

        

        由于回溯是暴力解锁的方式,为了实现性能优化,我们提前对于一些不可能搜到正确结果的树枝进行剪枝操作

1.暴力解锁的回溯

注意

        removeLast()是LinkedList的方法,List<>  list=new LinkedListM<>()是调用不到的。

        添加结果是,path的内容要复制给一个新的对象new LinkedList<>(),否则对同一个path对象修改的话,results记录的结果值也会发生改变,最终的结果就是result里面重复加入相同的path对象。。

  1. /**
  2. * 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合
  3. * @param n
  4. * @param k
  5. * @return
  6. */
  7. List<List<Integer>> results=new ArrayList<>();
  8. LinkedList<Integer> path = new LinkedList<>();
  9. public List<List<Integer>> combine(int n, int k) {
  10. backtracking(n,k,1);
  11. return results;
  12. }
  13. public void backtracking(int n,int k,int startIndex){
  14. //结果收集,结束
  15. if(path.size()==k){
  16. //重新new一个是因为如果对同一个path操作,最终result是一堆相同的path
  17. results.add(new ArrayList<>(path));
  18. return;
  19. }
  20. //未收集结果,遍历当前分支子孩子
  21. for(int i=startIndex;i<=n;i++){
  22. path.add(i);
  23. backtracking(n,k,i+1);
  24. path.removeLast();
  25. }
  26. }

2.采用剪枝的回溯

采用剪枝是为了在进行暴力的回溯搜索时,及时剪除不可能搜到正确结果的树枝,对整体搜索过程进行优化。

图摘自《代码随想录》

【剪枝优化】
从startIndex收集path
n-pathSize=还需要收集的数据量
n-statIndex=剩余的数据量
如果 k-pathSize<n-startIndex+1,则剩余的搜索,现有数据不足以搜到大小为k的组合
所以我们要保证k-pathSize<n-startIndex+1,变形得  startIndex<n-(k-pathSize)+1
  1. /**
  2. * 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合
  3. * @param n
  4. * @param k
  5. * @return
  6. */
  7. List<List<Integer>> results=new ArrayList<>();
  8. LinkedList<Integer> path = new LinkedList<>();
  9. public List<List<Integer>> combine(int n, int k) {
  10. backtracking(n,k,1);
  11. return results;
  12. }
  13. public void backtracking(int n,int k,int startIndex){
  14. //结果收集,结束
  15. if(path.size()==k){
  16. //重新new一个是因为如果对同一个path操作,最终result是一堆相同的path
  17. results.add(new ArrayList<>(path));
  18. return;
  19. }
  20. //未收集结果,遍历当前分支子孩子
  21. //【剪枝优化】
  22. for(int i=startIndex;i<=n-(k-path.size())+1;i++){
  23. path.add(i);
  24. backtracking(n,k,i+1);
  25. path.removeLast();
  26. }
  27. }

3.分析

时间复杂度:

        暴力回溯:O(2^n)

        剪枝回溯:O(\binom{n}{k}\times k)

空间复杂度:

        暴力回溯:O(k)

        简直回溯:O(k)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/84991
推荐阅读
相关标签
  

闽ICP备14008679号