「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」
组合总和
题目
给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出candidates 中所有可以使数字和为目标数 target 的唯一组合。candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。
对于给定的输入,保证和为 target 的唯一组合数少于 150 个。
示例 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]]
示例 3:
输入: candidates = [2], target = 1
输出: []
示例 4:
输入: candidates = [1], target = 1
输出: [[1]]
示例 5:
输入: candidates = [1], target = 2
输出: [[1,1]]
提示:
- 1 <= candidates.length <= 30
- 1 <= candidates[i] <= 200
- candidate 中的每个元素都是独一无二的。
- 1 <= target <= 500
解题思路
对于candidates = [2,3,6,7], target = 7,我们来分析他构建组合的思路,首先取一个数时,他有4种选择,选2,选3,选6,选7,对于每种选择的下一层递归而言,是需要在各自区间下取值,才能不尽相同,比如选2的,下一层要在[2,3,6,7]中选择;选3的,下一层要在[3,6,7]中选择,选6的,下一层要在[6,7]中选择,选7的只能在[7]这一区间相同,这样的递归过程构建成了一颗树的结构,当选取的数,相加和大于sum时,直接进入下一种选择,<sum的继续递归,在对应区间取值,等于sum的结束当前分支递归,将组合压入结果栈中。
- 递归的终止条件:当传入的sum大于target时,递归结束(剪枝),当传入的sum等于于target时,将组合压入结果栈中,递归结束
- 递归的传入参数和返回值:无返回值,传入当前sum,和当前已组合的数值集合
- 递归的单层逻辑:当选取的数,相加和大于sum时,直接进入下一种选择,<sum的继续递归,在对应区间取值,等于sum的结束当前分支递归,将组合压入结果栈中
var combinationSum = function(candidates, target) {
const selectNum = function(index,sum){
if (sum > target) return;
if (sum === target){
res.push(Array.from(path));
return;
}
// 初始有candidates.length取值区间,candidates.length种选择
for(let i = index; i < candidates.length; i++) {
let n = candidates[i];
// 该取值空间不满足要求,直接进行该层递归的下一选择
if(n > target - sum) continue;
path.push(n);
sum += n;
selectNum(i, sum);
path.pop();
sum -= n;
}
}
let res = [];
let path = [];
// 对数组排序,方便取值求和比较
candidates.sort()
selectNum(0,0);
return res;
};