Leetcode40:组合总和II
-
题目:
- 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
-
思路:集合(数组candidates)有重复元素,避免出现重复的组合。
- 去重:同一树层上的“使用过”
- 在candidates[i] == candidates[i - 1]相同的情况下:
- used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
- used[i - 1] == false,说明同一树层candidates[i - 1]使用过,在for循环中满足该条件,直接continue跳过
- 去重:同一树层上的“使用过”
-
代码如下:
class Solution {
//二维数组存放结果集
List<List<Integer>> res = new ArrayList<>();
//一维队列存放path路径
Deque<Integer> deque = new LinkedList<>();
int sum = 0;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
//标志候选人编号是否被使用
boolean[] flag = new boolean[candidates.length];
//回溯算法
backtracking(candidates,target,0,flag);
return res;
}
void backtracking(int[] candidates,int target,int index,boolean[] flag){
if(sum==target){
res.add(new ArrayList(deque));
return;
}
for(int i = index; i<candidates.length&&sum+candidates[i]<=target;i++){
//candidates[i]==candidates[i-1]&&used[i - 1] == false
//说明同一树层candidates[i - 1]使用过,即出现重复节点
if(i>0&&candidates[i]==candidates[i-1]&&!flag[i-1]){
continue;
}
sum += candidates[i];
flag[i] = true;
deque.push(candidates[i]);
backtracking(candidates,target,i+1,flag);
int tmp =deque.pop();
flag[i] = false;
sum -= candidates[i];
}
}
}