力扣 39 组合总和
文章目录
全部刷题与学习记录
原题目
题目地址:39. 组合总和
给定一个无重复元素的数组 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的数字可以无限制重复被选取。
说明:
所有数字(包括 target
)都是正整数。
解集不能包含重复的组合。
示例 1:
输入:candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入:candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
考查知识点
回溯法、回溯法的起点
自己的第一遍解法
本来是一道组合题(结果不带顺序),因为回溯法的起点设置错误,做成了一道排列题(结果带顺序)
按照【算法套路】-【回溯篇】【回溯三步法】提到的回溯三步法,来分析一下这道题
作为回溯问题,需要两个数组来记录路径path
与最终返回结果result
,同时这道题还要求计算路径path
内全部元素之和sum
1、回溯函数返回值及参数:返回值没什么好说的,就是void,参数首先要有题目所给的vector<int>& candidates
、int target
,其次还要有for循环开始的索引int index
2、回溯函数终止条件:有两种,1)sum == target
,此时将path
加入result
;2)sum > target
,此时直接回退
3、单层回溯逻辑:很显然for循环从起点开始,把当前遍历的数字加入path
中,在累计加和;撤销的时候也要对应path
弹出尾部元素,sum
减去弹出的元素。下面是重点,我自己在写程序的时候,不自觉就把for循环写成了这样:
//跟着感觉盲写回溯
for (int i = index; i < candidates.size(); ++i) {
//3:单层回溯逻辑
path.push_back(candidates[i]);
sum += candidates[i];
backTracking(candidates, target, index);
sum -= path.back();//回溯,撤销操作
path.pop_back();
}
输出结果:
2 2 3
2 3 2
3 2 2
7
//正确答案
for (int i = index; i < candidates.size(); ++i) {
//3:单层回溯逻辑
path.push_back(candidates[i]);
sum += candidates[i];
backTracking(candidates, target, i);//不必是i+1,表示重复读取当前的数
sum -= path.back();//回溯,撤销操作
path.pop_back();
}
输出结果:
2 2 3
7
注意差别就在于backTracking()
传入的最后一个index
形参出了问题,实参传进去index是没有意识顺手写出来的,这样每次向下递归都是从[2,3,6,7]的第一个元素开始,最后的输出答案就是一个排列问题的答案,但我们是一个组合问题,本题可以出现重复元素,那么我们就从i
的位置向下递归,也就是说,下次递归时,选择范围就要缩小到[i, 最后]
,[开始,i-1]
我们都是不考虑的,也就是搜索是向多叉树的右下角不断进行的。
一定要注意这个形参index
的传入实参,如果是实参index,index在全程没有改变,那么每次为形参index传入的都是0,这样就是一个排列问题,如果传入的是i
,那么每次向下递归,可供选择的范围就会缩小,这样才是一个回归问题。
本篇文章参考:代码随想录-回溯算法:求组合总和(二)