这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战
题目描述
给定一个数组 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 <= 100`
`1 <= candidates[i] <= 50`
`1 <= target <= 30`
复制代码
实现思路
这题乍一看跟上一篇的组合总和好像一样的,只是说不能用自己本身了,所以我先在组合总和代码的基础上先将candidates进行排序再将回调dfs(num - candidates[i], [...list, candidates[i]], i)改成了dfs(num - candidates[i], [...list, candidates[i]], i+1)最后通过set进行来添加答案以达到去重的效果,最后执行虽然也可以得到答案但是超出了时间限制,所以应该要更换去重的方法,在没有用set去重的时候我们可以发现相同数字得到的答案会有很多重复的,由于我们做了排序操作这样我们可以通过判断相邻位置的数字是否相同来略过回调已达到去重的效果,这样就可以降低事件复杂度得出题解了,以下是整体的代码实现。
代码实现解析:
- 对candidates升序处理
- 定义递归函数dfs
- 递归退出条件num==0说明选择的数字相加等于target
- i > start && candidates[i] == candidates[i - 1]相邻位置去重
- 执行完dfs(target, [], 0)返回res答案集合
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
var combinationSum2 = function(candidates, target) {
candidates.sort((x, y) => x - y) //升序
let res = []
let len = candidates.length
let dfs = function(num, list, start) { //递归
if (num == 0) {
res.push(list)
}
for (let i = start; i < len; i++) {
if (i > start && candidates[i] == candidates[i - 1]) continue //去重
if (num - candidates[i] >= 0) {
dfs(num - candidates[i], [...list, candidates[i]], i+1)
}
}
}
dfs(target, [], 0)
return res
};
复制代码