力扣77 组合
题目:
给定两个整数 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();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY