题目描述
给定一个可能有重复数字的整数数组 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]
]
思路
这道题和上一道题的区别在于,上一道题中给定的数组中没有重复的元素,而这道题的数组中有重复的元素。并且题目要求最后的解集中不能包含重复的组合。比如示例2中, candidates = [2,5,2,1,2],那么[2,2,1]和[2,1,2]都满足条件,但是他们确实一样的组合(组合不考虑排列顺序)。
那么如果避免出现相同的组合呢?
当我们决定跳过某一个数字时,同时也跳过后面所有和它相等的数字即可。
为了方便,我们可以先将数组排序。
比如示例2中, candidates = [2,5,2,1,2],排序后为[1,2,2,2,5]
假设现在执行到:已经选择了[1,2,2],此时sum==target,返回,那么该执行不选择他的那步操作了,即跳过第二个2,按照之前的说法,第三个2也要跳过,现在就指向了5。那么就不会出现第二个[1,2,2]了。
代码
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
List<List<Integer>> result = new LinkedList();
LinkedList<Integer> subset = new LinkedList();
dfs(candidates, target, 0, 0, subset, result);
return result;
}
private void dfs(int[] candidates, int target, int sum, int index, LinkedList<Integer> subset, List<List<Integer>> result){
if(sum == target){
result.add(new LinkedList(subset));
}else if(sum > target || index == candidates.length){
return;
}else{
dfs(candidates, target, sum, getNext(candidates, index), subset, result);
subset.add(candidates[index]);
dfs(candidates, target, sum + candidates[index], index + 1, subset, result);
subset.removeLast();
}
}
private int getNext(int[] candidates, int index){
int next = index;
while(next < candidates.length && candidates[next] == candidates[index]){
next++;
}
return next;
}
}