中文题目
给定一个可能有重复数字的整数数组 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
注意:本题与主站 40 题相同: https://leetcode-cn.com/problems/combination-sum-ii/
通过代码
高赞题解
我们定义dfs(idx, target)
为:
选中candidate[idx],同时与从下标为[idx + 1, candidate.length)中选取元素一起构成和为target的所有不重复组合的集合。
本题难点有二:
一、避免重复答案
为了避免重复的答案,首先我们要做的就是给数组排序,如果说我在同一级递归中,遇到两个相同的数,我们应该只dfs靠前的那一个一次。原因的话,我们可以这样理解,如果现在遇到下标位idx
,idx + 1
的两个数是相同的,那么对于集合dfs(idx, target)
和 dfs(idx + 1, target)
,后者就是前者的一个子集,所以我们在同一级递归中,对于相同的数,只应该dfs一次,并且是下标最小的那一个。
二、剪枝
剪枝就是基于很直接的思想,例如:前面已经给数组排序了,如果递归的过程中当前值比target大,那么说明后面的值不可能再找出一组元素和为target,所以此时就可以立即结束递归返回。
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
int n = candidates.length;
List<List<Integer>> ans = new ArrayList<>();
Arrays.sort(candidates);
dfs(candidates, n, 0, target, new ArrayList<>(), ans);
return ans;
}
public void dfs(int[] candidate, int n, int idx, int target, List<Integer> list, List<List<Integer>> ans) {
if (target == 0) {
ans.add(new ArrayList<>(list));
return ;
}
for (int i = idx; i < n; i++) {
if (candidate[i] > target) { // 剪枝
break;
}
if (i > idx && candidate[i] == candidate[i - 1]) { // 剪枝、避免重复
// 因为前面那个同样的数已经经历过dfs,再拿同样的数dfs就会得到重复的答案
continue;
}
list.add(candidate[i]);
dfs(candidate, n, i + 1, target - candidate[i], list, ans);
list.remove(list.size() - 1);
}
}
}
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
4203 | 6508 | 64.6% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|