leetcode 40. 组合总和 II---回溯篇3
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode 40. 组合总和 II---回溯篇3相关的知识,希望对你有一定的参考价值。
回溯法
解题思路:
一句话题解:按顺序搜索,设置合理的变量,在搜索的过程中判断是否会出现重复集结果。重点理解对输入数组排序的作用
与第 39 题(组合之和)的差别
这道题与上一问的区别在于:
- 第 39 题:candidates 中的数字可以无限制重复被选取;
- 第 40 题:candidates 中的每个数字在每个组合中只能使用一次。
相同点是:相同数字列表的不同排列视为一个结果。
如何去掉重复的集合(重点)
为了使得解集不包含重复的组合。有以下 22 种方案:
- 使用 哈希表 天然的去重功能,但是编码相对复杂;
- 使用和第 39 题和第 15 题(三数之和)类似的思路:不重复就需要按 顺序 搜索, 在搜索的过程中检测分支是否会出现重复结果 。注意:这里的顺序不仅仅指数组 candidates 有序,还指按照一定顺序搜索结果。
由第 39 题我们知道,数组 candidates 有序,也是 深度优先遍历 过程中实现「剪枝」的前提。
将数组先排序的思路来自于这个问题:去掉一个数组中重复的元素,看上图可知,是去掉后一个重复数字1
关键代码:if (i>index&&candidates[i] == candidates[i - 1]) continue;
i>index可以看上图,多叉树第一层可选数字有1,1,2.
显然选择第一个数字1的时候不需要考虑去重的问题,因此需要写i>index
如果不写,那么会产生溢出,因此一开始i=0而i-1=-1
代码:
class Solution {
vector<vector<int>> ret;
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
if (accumulate(candidates.begin(), candidates.end(), 0) < target) return ret;
vector<int> num;
sort(candidates.begin(), candidates.end());
backTrace(candidates, target,num,0);
return ret;
}
void backTrace(vector<int>& candidates, int target,vector<int>& num,int index)
{
if (target == 0)
{
ret.push_back(num);
return;
}
for (int i =index; i < candidates.size() && target - candidates[i] >= 0; i++)
{
if (i>index&&candidates[i] == candidates[i - 1]) continue;
num.push_back(candidates[i]);
backTrace(candidates, target - candidates[i], num, i+1);
num.pop_back();
}
}
};
哈希法去重
思路:
先对数组进行排序,然后使用set容器存储所有结果,当出现相同结果的时候,set容器会插入失败
但是注意一定要先对数组进行排序,如果不排序:[1,2,1]和[1,1,2]这样两个数组,set容器会认为两种不相等,排序后,两个数组就会都变成[1,1,2],这样插入第一个[1,1,2]后,遇到第二个[1,1,2]就会插入失败
代码:
class Solution {
set<vector<int>> ret;
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
if (accumulate(candidates.begin(), candidates.end(), 0) < target) return vector<vector<int>>();
vector<int> num;
sort(candidates.begin(), candidates.end());
backTrace(candidates, target,0,num);
vector<vector<int>> r;
return vector<vector<int>>(ret.begin(),ret.end());
}
void backTrace(vector<int>& candidates, int target,int index,vector<int>& num)
{
if (target == 0)
{
ret.insert(num);
return;
}
for (int i = index; i < candidates.size() && target - candidates[i] >= 0; i++)
{
num.push_back(candidates[i]);
backTrace(candidates, target - candidates[i], i + 1, num);
num.pop_back();
}
}
};
以上是关于leetcode 40. 组合总和 II---回溯篇3的主要内容,如果未能解决你的问题,请参考以下文章
递归与回溯7:LeetCode40. 组合总和 II(不可重复)