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(不可重复)

[leetcode 40. 组合总和 II] 不排序使用哈希表+dfs递归 vs 排序栈+回溯

算法 ---- LeetCode回溯系列问题题解

算法 ---- LeetCode回溯系列问题题解

算法 ---- LeetCode回溯系列问题题解

算法 ---- LeetCode回溯系列问题题解