回溯-组合问题
什么是组合问题?
从N个数里面,选K个数,一共有多少种组合方式?
最基本的回溯,我们需要注意 1. 终止条件 2. for 循环横向 3. 回溯纵向 4. 剪枝
如果要将回溯的过程可视化的话,我会选择画一个树,
回溯的过程就是 dfs 这个树的过程。
继续拓展之、、、
选K个数,和为target?
回溯三件套+终止条件+排序剪枝
N个数中没有重复数字,可以使用不限次数,如何?
回溯三件套+回溯时(递归调用时)curIndex 不变+排序剪枝
N个数中有重复数字,每个限用一次,如何?
回溯三件套 + 去重 (※)+ 排序剪枝
回溯三件套
- 确定参数和返回值
- 确定终止条件
- 确定遍历过程
template 如下👍
function backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {// 同层
处理节点;
backtracking(路径,选择列表); // 递归进入下一层
回溯,撤销处理结果 // 返回上一层
}
}
所谓层,是指 遍历树 的层,比如我要从 5 个数abcde中选 3 个,
选第一个时,我可以有 5 种选择,a/b/c/d/e,相应的有 5 个分支,
那么,对于某一个分支,我需要继续选第二个数,比如 a,此时即递归调用backtracking函数,
选第二个时,我只有 4 种选择,b/c/d/e,......
练习题目:
77. 组合
216. 组合总和Ⅲ
...
剪枝优化
有哪些优化手段呢?什么时候需要优化呢?
- 剩余节点不够选的时候
k - path.length > n - curIndex + 1
- 当前节点总和已经大于target
去重
N个数中有重复数字,每个限用一次,如何?
对于这个问题,我们需要去重,
首先将数组排好序,例如 1 2 2 4 5 ,
按照之前的做法,试想一下,第一个数选 1,
第二个数可以为 2 / 2 / 4 / 5,需要删除第二个 选 2 的分支
下图说明了为什么需要删除
代码实例:
40. 组合总和Ⅱ
function backTracking(target,sum,curIndex,candidates){
if(sum === target){
result.push([...path]);
return;
}
// 剪枝
for(let i = curIndex; i < candidates.length && sum + candidates[i] <= target; i++ ){
// 去重(巧妙🍎)
if( i > curIndex && candidates[i] === candidates[i-1]){
continue;
}
path.push(candidates[i]);
sum += candidates[i];
backTracking(target,sum,i + 1,candidates);
path.pop();
sum -= candidates[i];
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律