小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
题目
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
**注意:**解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5, 输出: [ [1,2,2], [5] ]
提示:
1 <= candidates.length <= 1001 <= candidates[i] <= 501 <= target <= 30
思路
回溯+减枝
和39题的区别
- 数组含有重复数字
- 每个数字只能选择一次
代码
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
var combinationSum2 = function(candidates, target) {
if (candidates.length < 0) {
return [];
}
// 排序
candidates.sort((a, b) => parseInt(a) - parseInt(b));
this.backtrack = function(candidates, list, start, target) {
if (target == 0) {
res.push(list.slice());
return;
}
for (let i = start; i < candidates.length; i++) {
// 减枝:因为target小于candidates[i],candidates升序,所以candidates从i+1后面的数肯定大于target,直接break 进行减枝
if (target < candidates[i]) {
break;
}
// 减枝:跳过重复的数字,重复的不选择
if (i > start && candidates[i] == candidates[i-1]) {
continue;
}
list.push(candidates[i]);
// i位置的选择的,所以从i+1开始选
backtrack(candidates, list, i + 1, target - candidates[i]);
list.pop();
}
}
let res = [];
let list = [];
backtrack(candidates, list, 0, target);
return res;
};
复杂度
- 时间O(n*2^n)
- 空间O(target),取决于递归的栈深度
思路2
最近的每日一题基本都是递归回溯型,相比组合总数这题,多了一个不能重复使用数字的条件。故首先对数组进行排序,使得重复的数字相邻,若当前数字等于前一个数字则跳出循环进入下一个数字。
代码
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
var combinationSum2 = function(candidates, target) {
var res = [], temp = []; //res保存结果,temp保存当前选择的数字
var sum = 0; //当前数字和
var len = candidates.length;
candidates.sort((a, b) => { return a - b}); //排序
dfs(0);
return res;
function dfs(k) {
if(sum >= target) {
if(sum == target) {
res.push(temp.slice()); //满足条件,复制一份放入结果
}
return;
}
for(let i = k; i < len; i++) {
if(target < candidates[i]) break; //如果当前将要值已经大于目标值直接退出循环
if(i > k && candidates[i] == candidates[i - 1]) continue; //重复的情况
sum += candidates[i];
temp.push(candidates[i]);
dfs(i + 1); //递归
temp.pop(); //回溯
sum -= candidates[i];
}
}
};