力扣40:
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
解题思路: 回溯算法解决问题
重点就是如何进行递归。递归的第一步,当然是写递归的终止条件啦,没有终止条件的递归会进入死循环。那么有 哪些终止条件呢?由于条件中说了都是正整数。因此,如果 target<0,当然是要终止了,如果 target==0,说明此时找到了一组数的和为 target,将其加进去。
1:判断重复去重复(同一个父节点的子节点必须是不同的值 方法:排序+hash判断) 可以用NEW SET方法。(ES6)
2:找到目标,后面的不会存在最优解。设计动态规划,还不太明白。
时间复杂度:O(n!)
空间复杂度:O(1)
const combinationSum2 = (candidates, target)=>{
let res=[],res0=[];
candidates.sort();//
const dfs=(k,idx,tgt)=>{
if(tgt===0){
// console.info(JSON.stringify(res0.slice(0,k)));//slice() 方法可从已有的数组中返回选定的元素。找到了,终止条件,把RES0里面的值存到 RES中,选定下标为0到K
res.push(JSON.stringify(res0.slice(0,k)));
}else{
for (let i=idx;i<candidates.length;i++){//继续循环,
if(tgt-candidates[i]>=0){
res0[k]=candidates[i];//先存一个数,再凑一个数
dfs(k+1,i+1,tgt-candidates[i]);//递归下一次,找到第二个子数组的值
}
}
}
};
dfs(0,0,target);//从0开始遍历
return [...new Set(res)].map(item=>JSON.parse(item));//把字符串转换成数组,RES0是临时存储,RES返回最后的结果,最后去重一下
};