题目
- 组合总和 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]
]
思路(注意事项)
组合中,统一集合有重复元素,单一输出结果 输出可以用重复元素,但是输出的总结果集合不能有重复集合。
纯代码
class Solution {
private:
vector<int> path;
vector<vector<int>> ans;
void backtracking(vector<int>& candidates, int target, int sum, int start)
{
if (sum == target) {
ans.push_back(path);
return;
}
for (int i = start; i < candidates.size() && sum + candidates[i] <= target; i++) {
if (i > start && candidates[i] == candidates[i - 1]) continue;
sum += candidates[i];
path.push_back(candidates[i]);
backtracking(candidates, target, sum, i + 1);
sum -= candidates[i];
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
backtracking (candidates, target, 0, 0);
return ans;
}
};
题解(加注释)
class Solution {
private:
vector<int> path; // 当前路径
vector<vector<int>> ans; // 结果集合
// 回溯函数 (需注意三个关键点:排序、去重、索引递增)
void backtracking(vector<int>& candidates, int target, int sum, int start) {
// 终止条件:找到有效组合
if (sum == target) {
ans.push_back(path);
return;
}
// 遍历候选集 (start保证顺序,避免重复组合)
for (int i = start;
i < candidates.size() && sum + candidates[i] <= target; // 剪枝:提前终止无效分支
i++)
{
// 去重关键:跳过同一层的重复元素 (i > start保证保留不同层的相同元素)
if (i > start && candidates[i] == candidates[i - 1]) continue;
// 选择当前元素
sum += candidates[i];
path.push_back(candidates[i]);
// 递归处理下一层 (i+1保证元素不重复使用)
backtracking(candidates, target, sum, i + 1);
// 撤销选择
sum -= candidates[i];
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
// 关键预处理:排序 (方便剪枝和去重)
sort(candidates.begin(), candidates.end());
// 启动回溯
backtracking(candidates, target, 0, 0);
return ans;
}
};