组合总和 II
给定一个候选人编号的集合 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
思路:
- 我们需要限制相等元素在每一轮中只被选择一次。实现方式比较巧妙:由于数组是已排序的,因此相等元素都是相邻的。这意味着在某轮选择中,若当前元素与其左边元素相等,则说明它已经被选择过,因此直接跳过当前元素。
- 与此同时,本题规定中的每个数组元素只能被选择一次。幸运的是,我们也可以利用变量 index 来满足该约束:当做出选择后,设定下一轮从索引 i+1 开始向后遍历。这样即能去除重复子集,也能避免重复选择元素。
代码:
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
backtrack(candidates,target,0);
return res;
}
public void backtrack(int[] candidates, int target,int index){
if(target == 0) {
res.add(new ArrayList<Integer>(path));
return;
}
if(target<0) return;
for(int i=index;i<candidates.length;i++) {
if (target - candidates[i] < 0) {
break;
}
// 如果该元素与左边元素相等,说明该搜索分支重复,直接跳过
if (i > index && candidates[i] == candidates[i - 1]) {
continue;
}
path.add(candidates[i]);
backtrack(candidates,target-candidates[i],i+1);
path.remove(path.size()-1);
}
}
}