40. 组合总和 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]
]
思路分析:
回溯法:
回溯的三步曲.
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
本题的难点在于 ,需要对收集到的元素进行去重。
处理逻辑:
- 对给定的数组进行排序 。
2 . 使用一个 used数组来记录我们已经遍历过的元素 , 如果当前的遍历的元素 ,已经被使用过了 ,那么我们就跳过该元素。
具体的代码实现:
class Solution {
public:
void backtraking(vector<int>&candidates ,int &target ,int index ,vector<bool>&used){
if(target == 0 ){
//收集结果集
ret.push_back(temp);
return ;
}
if(target < 0){
return ;
}
for(int i = index ; i<candidates.size() ;i++){
if( i > 0 && candidates[i] == candidates[i-1] && used[i-1] == 0 ) continue;
temp.push_back(candidates[i]);
used[i] = true; //记录已经遍历过的元素
target -= candidates[i];
backtraking(candidates ,target ,i+1 ,used);
//回溯
temp.pop_back();
target += candidates[i];
used[i] = false;
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
if(candidates.size() == 0 ) return ret;
vector<bool>used(candidates.size() ,false); //记录元素使用的情况
sort(candidates.begin() , candidates.end()); //排序
backtraking( candidates ,target ,0 ,used);
return ret;
}
private:
vector<int>temp;
vector<vector<int>>ret;
};