组合总数
一、题目描述
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数
target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
示例 1:
输入:candidates = [2,3,6,7], target = 7 输出:[[2,2,3],[7]] 解释: 2 和 3
可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。 7 也是一个候选, 7 = 7 。 仅有这两种组合。
示例 2:
输入: candidates = [2,3,5], target = 8 输出: [[2,2,2,2],[2,3,3],[3,5]]
示例3:
输入: candidates = [2], target = 1 输出: []
二、思路
一道比较经典的回溯题。
首先 画树,把7的所有可能分出来的情况给列出来(不减枝的话就是暴力了)

我们就让目标值当作根,然后减去当前的数字(记录当前数字 进栈),再继续向下(DFS),减去数字 继续进栈,直到节点的小于等于0;
等于0说明 7减去这些数字可能变成0,是一种方案。我们就需要将栈中存放的数字排好序保存。(为什么要排序?往下看)
如果小于等于0了之后,我们就需要向上走( 即回溯 ),回溯时注意,要将栈顶数字退栈,去其他分支继续深搜。
最终得到的答案 会有重复了,例如上图。 223 232 322 都应该算一种。
所有我们需要去重!
方法是:将所有结果都排序再保存,这样 我们就会得到三个 [223],然后可以利用set自动去重,再复制到vector数组中。

没有减枝的时间复杂度。
时间复杂度太高了。没有减枝的回溯就是暴力美学了啊。。。
减枝的话 只想到了如果减去当前数等于负数了,那么没必要再检查其他大数的分支了。
所以,我们还需要对初始给的数组进行排序(它给不是默认排好序的 不要被样例骗了,见测试用例74)

确实是快了 ,但为啥还是击败 5%? 😦
三、代码
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<int> temp;
vector<vector<int>> ans;
dfs(candidates,ans,temp,target);
//使用set去重
set<vector<int>> s(ans.begin(),ans.end());
vector<vector<int>> ans2;
//将set 再复制给 vector
ans2.assign(s.begin(),s.end());
return ans2;
}
void dfs(vector<int> &candidates,vector<vector<int>> &ans,vector<int> temp, int target){
if(target<0){
temp.pop_back();
return;
}
if(target==0){
//排序为了去重
sort(temp.begin(),temp.end());
ans.push_back(temp);
temp.pop_back();
return;
}
for(int i=0;i<candidates.size();i++){
temp.push_back(candidates[i]);
//进入到下一层
dfs(candidates,ans,temp,target-candidates[i]);
//回溯到上一层
temp.pop_back();
}
}
};
减枝:
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<int> temp;
vector<vector<int>> ans;
sort(candidates.begin(),candidates.end());
dfs(candidates,ans,temp,target);
//使用set去重
set<vector<int>> s(ans.begin(),ans.end());
vector<vector<int>> ans2;
//将set 再复制给 vector
ans2.assign(s.begin(),s.end());
return ans2;
}
void dfs(vector<int> &candidates,vector<vector<int>> &ans,vector<int> temp, int target){
if(target==0){
//排序为了去重
sort(temp.begin(),temp.end());
ans.push_back(temp);
temp.pop_back();
return;
}
for(int i=0;i<candidates.size();i++){
//减枝!
if(target<candidates[i]){
break;
}
temp.push_back(candidates[i]);
//进入到下一层
dfs(candidates,ans,temp,target-candidates[i]);
//回溯到上一层
temp.pop_back();
}
}
};
本文介绍了一道关于寻找数组中数字组合使得和为目标数的回溯算法题目。通过建立搜索树并进行深度优先搜索,同时讨论了如何进行减枝优化以提高效率。代码示例展示了如何实现排序、回溯和去重操作,以找到所有可能的组合。文章还提及了未进行减枝时的时间复杂度问题。
1589

被折叠的 条评论
为什么被折叠?



