难度:中等
给定一个无重复元素的数组 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]
]
提示:
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate 中的每个元素都是独一无二的。
1 <= target <= 500
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:知道用回溯法,但是有些细节拿捏不准,看到力扣题解上的这个思路比较好理解
题意
给你一个数组,里面都是不带重复的正数,再给定 target,求出所有和为 target 的组合。
元素可以重复使用,但组合不能重复,比如 [2, 2, 3] 与 [2, 3, 2] 是重复的组合。
思路在图里
×表示:当前组合和之前生成的组合重复了,比如最左边的×: 2232,与之前生成过的 2223 重复(虽然它 > target 被舍弃了)
△表示:当前的求和超出 target,不能选下去了,返回。
○表示:求和正好等于 target,加入解集,并返回。
利用约束条件剪枝
后两个约束条件很简单,设置递归结束条件:
if (sum >= target) {
if (sum == target) {
res.push(temp.slice()); // 加入解集
}
return; // 结束当前递归
}
不产生重复组合怎么限制(剪枝)?
如上图,只要限制下一次选择的起点,是基于本次的选择,这样下一次就不会选到本次选择的同层左边的数。即通过控制 for 遍历的起点,去掉会产生重复组合的选项。
for (let i = start; i < candidates.length; i++) { // 枚举当前可选的数,从start开始
temp.push(candidates[i]); // 选这个数
dfs(i, temp, sum + candidates[i]); // 基于此,继续选择,传i,下一次就不会选到i左边的数
temp.pop(); // 撤销选择,回到选择candidates[i]之前的状态,继续尝试选同层右边的数
}
注意,子递归传了 i 而不是 i+1 ,因为元素可以重复选入集合,如果传 i+1 就不重复了。
作者:xiao_ben_zhu
链接:https://leetcode-cn.com/problems/combination-sum/solution/shou-hua-tu-jie-zu-he-zong-he-combination-sum-by-x/
来源:力扣(LeetCode)
JavaScript解法:
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
var combinationSum = function(candidates, target) {
const res = [];
const dfs = (start, temp, sum) => { // start是当前选择的起点索引 temp是当前的集合 sum是当前求和
if (sum >= target) {
if (sum == target) {
res.push(temp.slice()); // temp的拷贝 加入解集
}
return; // 结束当前递归
}
for (let i = start; i < candidates.length; i++) { // 枚举当前可选的数,从start开始
temp.push(candidates[i]); // 选这个数
dfs(i, temp, sum + candidates[i]); // 基于此继续选择,传i,下一次就不会选到i左边的数
temp.pop(); // 撤销选择,回到选择candidates[i]之前的状态,继续尝试选同层右边的数
}
};
dfs(0, [], 0); // 最开始可选的数是从第0项开始的,传入一个空集合,sum也为0
return res;
};