一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情。
前言
每天一道算法题,死磕算法
题目
给定一个候选人编号的集合 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]
]
分析
- candidates是一个乱序的,所以我们要进行排序
- candidates 有可能为空,所以我们进行空数组判断,返回[]
- 因为candidates中包含重复的值,所以我们要剪枝
首先把我们的子集/组合的需要剪枝的模板拿出来
function backTrack(track:number[], nums:number[], start:number, result) {
// 把所有结果都放到结果中
result.push(track.slice());
// start来控制树的生长
for (let i = start; i < nums.length; i++){
track.push(nums[i]);
backTrack(track, nums, i + 1, result);
track.pop();
}
}
所以这个题目只和我们ts算法题解(第38天)----leetcode 77. 组合和90. 子集 II中的题目,差了一个变量路径和,也就是trackSum,只要我们用trackSum一直进行记录,就可以得到哪些track和为target了
我们直接上题解
题解
function backTrace(track:number[],nums:number[],start:number,target:number,trackSum,result):void{
if(trackSum === target){
result.push(track.slice());
return;
}
if(trackSum > target){
return;
}
for(let i = start;i<nums.length;i++){
if(i>start&&nums[i]===nums[i-1]){
continue;
}
// 做选择
track.push(nums[i]);
trackSum+=nums[i];
backTrace(track,nums,i+1,target,trackSum,result);
track.pop();
trackSum-=nums[i];
}
}
function combinationSum2(candidates: number[], target: number): number[][] {
let result = [];
if(!candidates.length){
return result;
}
// 先排序,让相同的元素靠在一起
candidates = candidates.sort();
let track = [];
let trackSum = 0;
let start = 0;
backTrace(track,candidates,start,target,trackSum,result)
return result;
};