组合总和

如题,这道题的回溯三要素比较直接,循环遍历时候剪枝不会太复杂。
- 终止条件:和为target,或者超出target就终止
- 返回值和参数:void,需要一个数记录遍历时起始的位置startIndex(先对candidates数组升序排序,从而保证枚举过程有序进行)
- 当层处理逻辑:
- 循环遍历从startIndex到让path的和不小于target的值为止,
- 当前值放入path中,path_sum加上该数
- 回溯下一层,
- path把当前值pop出来,path_sum减去该值
代码如下(执行用时击败5.54%,消耗内存击败4.95%):
class Solution {
private:
vector<int> path;
int path_sum;
vector<vector<int>> ans;
void backtrack(vector<int> candidates,int target,int startIndex){
if(path_sum>=target){
if(path_sum==target){
ans.push_back(path);
}
return;
}
int len = candidates.size();
for(int i = startIndex;i<len;i++){
path.push_back(candidates[i]);
path_sum += candidates[i];
backtrack(candidates,target,i);
path_sum -= candidates[i];
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
path_sum = 0;
backtrack(candidates,target,0);
return ans;
}
};
这份代码直接这样写的效率比较低,对比代码随想录的优化方法,回溯“剪枝”放在递归调用上(执行用时击败100.0%,消耗内存击败27.56%):
class Solution {
private:
vector<int> path;
int path_sum;
vector<vector<int>> ans;
void backtrack(vector<int> candidates,int target,int startIndex){
if(path_sum==target){
ans.push_back(path);
return;
}
int len = candidates.size();
for(int i = startIndex;i<len;i++){
path.push_back(candidates[i]);
path_sum += candidates[i];
if(path_sum<=target) backtrack(candidates,target,i); //在递归调用前,先剪枝
path_sum -= candidates[i];
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
path_sum = 0;
backtrack(candidates,target,0);
return ans;
}
};
提前在函数调用前判断是否需要递归调用,从而省去调用函数的消耗。
这道题,和之前的优化角度不一样,前面的回溯题优化主要是在研究如何剪枝,这一道题,没有太多可以剪枝的部分,就在函数调用次数尽可能少方面下功夫。
1185

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



