题目描述
给定一个候选人编号的集合 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
解题方法
dfs
这道题和第39题差不多,只是dfs写法略有区别,没看过的童鞋可以先看第39题。
这道题候选数组包含了重复数字,相比39题dfs的解法有点区别:
- 每次dfs遍历时,若当前遍历数字与前一个数字相同,则当前dfs中包含该数字的有效集合都已遍历过,为了解集不包含重复的组合,需要跳过该数字。
- 当前参与计算的数字之和小于
target
时,继续dfs。因为每个数字不能重复使用,所以下一次的dfs起始位置为下一个数字。
java代码
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(candidates);
List<Integer> curNums = new ArrayList<>();
dfs(candidates, target, result, curNums, 0, 0);
return result;
}
/**
* @param candidates 从小到大排序后的候选数组
* @param target 目标值
* @param result 结果集集合,是个引用
* @param curNums 当前参与计算的数字集合
* @param curSum 当前参与计算的数字之和
* @param start dfs遍历数组开始的位置
*/
public void dfs(int[] candidates, int target, List<List<Integer>> result, List<Integer> curNums, int curSum, int start) {
for (int i = start; i < candidates.length; i++) {
// 如果当前数字与前一个数字相同,说明当前dfs中包含该数字的有效集合都已遍历过,不需要再次遍历
if (i != start && candidates[i] == candidates[i - 1]) {
continue;
}
// 当前参与计算的数字之和等于target,添加结果集,并跳出当前dfs
if (curSum + candidates[i] == target) {
curNums.add(candidates[i]);
// 添加结果集的时候需要再new一个list,不然会添加引用,引用会不断变化。
result.add(new ArrayList<>(curNums));
curNums.remove(curNums.size() - 1);
return;
}
// 当前参与计算的数字之和大于target,直接跳出当前dfs(因为数组都是正数,所以不会越加越小)
if (curSum + candidates[i] > target) {
return;
}
// 当前参与计算的数字之和小于target,继续dfs,不过下一次的dfs起始位置start为i+1
curNums.add(candidates[i]);
dfs(candidates, target, result, curNums, curSum + candidates[i], i + 1);
curNums.remove(curNums.size() - 1);
}
}
复杂度分析
时间复杂度:
O
(
1
)
O(1)
O(1),target
最大为30,candidates
数组中最小值是1,所以dfs最大深度为30,数组长度为100,30 * 100为常数级别。
空间复杂度:
O
(
1
)
O(1)
O(1),dfs最大深度为30,递归调用的存储空间是常数级别。
相似题目
[leetcode] 17. 电话号码的字母组合
[leetcode] 22. 括号生成
[leetcode] 37. 解数独
[leetcode] 38. 外观数列
[leetcode] 39. 组合总和
- 个人公众号
- 个人小游戏