思路:
题目的主要信息:
- 从数组num找出所有加起来等于target的组合
- 每个组合num中每个元素只能用1次
- 返回的值必须是非递减次序,组合不能重复
方法一:递归+枝剪
具体做法:
对于排序后的num数组中第一个元素,我们可以考虑如果它比target大,那么后续都会比target大,没有加起来等于target的组合;但是如果它比target,我们可以考虑要不要将其加入待选路径(待选组合)中,如果没有加入(重复了),考虑下一个元素,target不变,如果加入了待选路径,考虑下一个元素的时就需要,由此转化成了一个子问题,递归结束的点就是
或者数组遍历结束。
因此,我们可以遍历数组,对于每个数使用递归,找到所有加起来等于目标值的组合,期间需要枝剪掉重复的组合。
class Solution {
public:
vector<vector<int> > res;
vector<int> path;
void dfs(int start, int target, vector<int> &num) {
if (target == 0) {
res.push_back(path); //target为0,不用再增加路径了,加入答案中
return;
}
for (int i = start; i < num.size() && target - num[i] >= 0; i++) {
if (i > start && num[i] == num[i - 1])
continue;
path.push_back(num[i]);
// 元素不可重复利用,使用下一个
dfs(i + 1, target - num[i], num);
path.pop_back(); //回溯
}
}
vector<vector<int> > combinationSum2(vector<int> &num, int target) {
sort(num.begin(), num.end()); //排序
dfs(0, target, num);
return res;
}
};复杂度分析:
- 时间复杂度:
,其中sort排序是
,因为远小于后面二者相乘,因此忽略不计,遍历一次为
,树型递归为
- 空间复杂度:
,递归栈深度和记录路径的辅助数组
方法二:哈希表+回溯
具体做法:
同样采用方法一的回溯,不过这才我们不直接排序,而是借助map(依赖红黑树的排序)。map中维护的是num数组中的元素及出现次数。
之后我们递归的时候不再遍历数组,而是遍历map,不过由于有的数字在数组有多个,因此我们需要从多到少(即第一次加入全部的该数,依次减少,最后加入一个,因为map有序,后面的数都比它大,遵从题目要求小的在前的目的)将其加入待选路径后再继续递归,这也是一种去重的方式。
class Solution {
public:
vector<vector<int> > res;
vector<int> path;
void dfs(int target, map<int,int>& mp, map<int, int>::iterator iter)
{
//递归终止条件,target等于零或小于排序
if (target == 0)
{
res.push_back(path);
return;
}
if(iter == mp.end() || target < iter->first)
return;
//从iter迭代器开始向后继续查找,因为map红黑树自动排序,所以是从小到大顺序的
for(auto i = iter; i != mp.end(); i++)
{
//考虑一个数出现多个时的情况
for(int j = i->second; j > 0; j--) //索引小数在前
{
for(int k = 0; k < j; k++)
path.push_back(i->first);
dfs(target - i->first * j, mp, ++i);
i--; //回溯
for(int k = 0; k < j; k++)
path.pop_back();
}
}
}
vector<vector<int> > combinationSum2(vector<int> &num, int target) {
map<int, int> mp;
//先把数据的频数用map保存起来
for(int i = 0; i < num.size(); i++){
if(mp.find(num[i]) != mp.end())
mp[num[i]]++;
else
mp[num[i]] = 1;
}
auto iter = mp.begin();
//深度优先算法
dfs(target, mp, iter);
return res;
}
};复杂度分析:
- 时间复杂度:
,其中初始化map是
,因为远小于后面二者相乘,因此忽略不计,遍历一次map最大为
,树型递归为
- 空间复杂度:
,递归栈及map的空间

京公网安备 11010502036488号