题目链接
回溯
本题的难点在于:集合(数组candidates)有重复元素,但还不能有重复的组合。
思想:元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。所以要去重的是同一树层上的“使用过”,同一树枝上的都是一个组合里的元素不用去重。
树层去重的话,需要对数组排序
去重逻辑:
如果candidates[i] = =candidates[i - 1] && used[i - 1] = = false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]。
used[i - 1] = true,说明同一树枝candidates[i - 1]使用过 used[i - 1] =
false,说明同一树层candidates[i - 1]使用过
为什么 used[i - 1] = false 就是同一树层呢?
- 因为同一树层,used[i - 1] = false 才能表示,当前取的 candidates[i] 是从 candidates[i - 1] 回溯而来的。
- 而 used[i - 1] == true,说明是进入下一层递归,去下一个数,所以是树枝上
class Solution {
List<List<Integer>> res = new ArrayList<List<Integer>>();
List<Integer> list = new ArrayList<Integer>();
boolean[] used;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
used = new boolean[candidates.length];
Arrays.fill(used, false);
Arrays.sort(candidates);
backtracking(candidates, target, 0, 0);
return res;
}
public void backtracking(int[] candidates, int target, int sum, int startIndex){
if(sum > target){
return;
}
if(sum == target){
res.add(new ArrayList<>(list));
return;
}
// used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
// used[i - 1] == false,说明同一树层candidates[i - 1]使用过
for(int i = startIndex; i < candidates.length; i++){
if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) {
continue;
}
// 下一层递归
used[i] = true;
sum += candidates[i];
list.add(candidates[i]);
backtracking(candidates, target, sum, i + 1);
used[i] = false;
sum -= candidates[i];
list.removeLast();
}
}
}