> 文档中心 > leetcode 40. 组合总和 II---回溯篇3

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();}}};

在这里插入图片描述