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]
]
解题思路:
问 答 有什么办法做到不重复? 两步走,详细见下文 递归终止条件 判断路径总和等于目标 单层逻辑 遍历从当前坐标开始,逐个开始递归后面的数字 参数 原来函数的参数,还需要加上一个start表示开始位置.一个sum来记录路径总和. 剪枝 因为先排序,所有如果路径总和加上当前的数大于目标时,那么后面的数就不需要遍历了.因为都会超过. 遇到这种需要不重复的,我们需要的就是在原来递归的基础上做多两步.
- 排序数组,让相同的数字相邻
- 用一个参数来表示开始位置(start),数字往后递归.避免重复
代码:
class Solution {
private:
//用来存储结果和去重,去的是两个相同数字在一起时的起点,也可以用flag标记是否遍历过这个数字.
vector<vector<int>> res;
vector<int>path;
public:
//递归回溯
//candidates,target 是原来的参数
//start表示起始位置
//sum表示路径总和
void backstrack(vector<int>& candidates, const int& target,const int& start,int sum)
{
//如果路径总和等于目标就说明找到了一种可能
if (sum == target)
{
res.push_back(path);
return;
}
//从当前下标开始,如果路径总和加上当前的数字大于目标总和.那么就不需要再遍历了
for (int i = start; i < candidates.size() && sum + candidates[start] <= target; i++)
{
//如果同一层不是第一个的同时遇到重复的就不需要再压入了,这样就可以出去相同的结果
if(i>start&&candidates[i]==candidates[i-1])
{
continue;
}
//添加路径节点
path.push_back(candidates[i]);
//计算路径长度
sum += candidates[i];
//下一位开始递归
backstrack(candidates, target, i + 1, sum);
//回溯
sum -= candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
//先排序,让相同的数相邻出现
sort(candidates.begin(),candidates.end());
//递归
backstrack(candidates, target, 0, 0);
//返回结果
return vector<vector<int>>(res.begin(),res.end());
}
};
总结:
记住回溯过程如果需要不重复.那么需要再加上两步即可.