题目:
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。
示例:
输入:n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
思路:
要解决 n为100,k为50的情况,暴力写法需要嵌套50层for循环,那么回溯法就用递归来解决嵌套层数的问题。递归来做层叠嵌套(可以理解是开k层for循环),每一次的递归中嵌套一个for循环,那么递归就可以用于解决多层嵌套循环的问题了。
每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围。图中可以发现n相当于树的宽度,k相当于树的深度。图中每次搜索到了叶子节点,我们就找到了一个结果。相当于只需要把达到叶子节点的结果收集起来,就可以求得 n个数中k个数的组合集合。
class Solution { //组合问题:N个数里面按一定规则找出k个数的集合 List<List<Integer>> res=new ArrayList<>(); LinkedList<Integer> path=new LinkedList<>(); public List<List<Integer>> combine(int n, int k) { combineback(n,k,1); return res; } //1.回溯函数模板返回值以及参数 public void combineback(int n,int k, int startIndex){ //2.回溯函数终止条件 if(path.size()==k){//找到叶子节点 res.add(new ArrayList<>(path)); //res.add(new ArrayList(path)):开辟一个独立地址,地址中存放的内容为path集合,后续path的变化不会影响到res。 //res.add(path):将res尾部指向了path地址,后续path内容的变化会导致res的变化。 return; } //3.回溯搜索的遍历过程 for(int i=startIndex;i<=n;i++){ path.add(i);//处理节点 combineback(n, k, i + 1);//递归 path.removeLast();//回溯,撤销处理结果 } } }
剪枝处理:
看一下优化过程如下:
-
已经选择的元素个数:path.size();
-
还需要的元素个数为: k - path.size();
-
在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历
为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。
遍历部分可改为:
for (int i=startIndex;i<=n-(k-path.size())+1;i++){ path.add(i); combineHelper(n, k, i + 1); path.removeLast(); }
标签:77,组合,int,res,个数,力扣,new,path,size From: https://www.cnblogs.com/cjhtxdy/p/17165896.html