回溯算法,有重复元素的非重复组合40. 组合总和 II
leetcode40. 组合总和 II
题目:
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
题解:
候选编号是可以重复的,也就是说,如果有个集合[10,1,2,7,6,1,5],里面有两个1,虽然每个数字在组合中只能使用一次,但是组合中可以出现两个1。如何去保证解集不包含重复的组合呢?
首先分析一下怎么做会出现重复的组合,这是因为编号集合里边有相同的元素,顺序回溯的话容易造成重复,解决方法如下。
首先,对编号集合做一个排序,让相同的元素在一起,然后我们考虑一下回溯的过程,所有的回溯问题都可以看作是多叉树的结构,我们选择一个元素之后,会进入树的下一层选择其后的元素,这样是合法的,也就是说,在树枝上重复是没有问题的,但是,考虑这样一种情况,有两个相同的元素,对第一个元素执行递归查找后,这个元素实际上包含了其后一个相同元素的全部情况,也就是说,不应该对其后的相同元素进行递归,从而就能避免出现重复的组合。
代码如下:
class Solution {
public:
vector<vector<int>> result;
vector<int> subResult;
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
com(candidates, target, 0);
return result;
}
void com(vector<int>& candidates, int target, int n){
if(target == 0){
result.push_back(subResult);
}else if(target < 0){
return;
}
for(int i = n; i < candidates.size(); i++){
subResult.push_back(candidates[i]);
//树枝向下递归的时候不要去重
com(candidates, target- candidates[i], i + 1);
//这里执行树层间的去重操作(因为层间前一个相同元素完全覆盖后一个相同元素的组合情况)
while(i + 1 < candidates.size() && candidates[i] == candidates[i+1]){
i++;
}
subResult.pop_back();
}
return;
}
};