Leetcode39
1.问题描述
2.解决方案
解法一:普通回溯
1.本题目和之前的组合一的不同在于,本题元素可以重复,所以在递归传参的时候就有区别,传入i就好,而不是i+1
backtracking(candidates,target,sum,i);
2.本题目和之前的组合一的不同在于,本题没有数量要求,所以递归终止只靠sum和target的关系
if(sum>target) return;
if(sum==target){
ans.push_back(path);
return;
}
3.本题还是需要使用startIndex来控制for,因为是同一集合求组合问题
class Solution {
public:
vector<vector<int> > ans;
vector<int> path;
void backtracking(vector<int>& candidates,int target,int sum,int startIndex){
if(sum>target) return;
if(sum==target){
ans.push_back(path);
return;
}
for(int i=startIndex;i<candidates.size();i++){
sum+=candidates[i];
path.push_back(candidates[i]);
backtracking(candidates,target,sum,i);
sum-=candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
backtracking(candidates,target,0,0);
return ans;
}
};
解法二:排序剪枝回溯(在求和问题中,排序之后剪枝是很重要的套路)
1.首先确定我们剪枝的目标是如果不符合条件干脆就在递归入口时停止递归,而不是在进入递归后再判断,所以我们就要在递归入口排除sum加上本层的candidates[i]大于target的情况,如果大于干脆不进去递归而不是进入递归后返回
//if(sum>target) return;
if(sum==target){
ans.push_back(path);
return;
}
for(int i=startIndex;i<candidates.size()&&sum+candidates[i]<=target;i++)
2.当然如果这样判断必须保证集合是有序的
sort(candidates.begin(),candidates.end());
class Solution1 {
public:
vector<vector<int> > ans;
vector<int> path;
void backtracking(vector<int>& candidates,int target,int sum,int startIndex){
//if(sum>target) return;
if(sum==target){
ans.push_back(path);
return;
}
for(int i=startIndex;i<candidates.size()&&sum+candidates[i]<=target;i++){
sum+=candidates[i];
path.push_back(candidates[i]);
backtracking(candidates,target,sum,i);
sum-=candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
backtracking(candidates,target,0,0);
return ans;
}
};
Leetcode40
1.问题描述
2.解决方案
本题特点:同一集合,元素有相同但不可以重复选,组合不能重复
1.去重(树层去重,树枝去重) ,由于本题有相同元素但还要求组合不能重复所以去重就很重要,去重当然也得对数组排序,如果同一层使用了相同的元素会出现重复的组合,同一树枝不会有重复的组合,看图就会发现这个判断条件
if(i-1>=0&&candidates[i]==candidates[i-1]&&used[i-1]==false) continue;
2.回溯递归函数参数和终止条件都没什么可说的,只多了一个used数组用来标记元素是否使用过用来去重
3.同一集合当然需要startIndex
4.剪枝都不多说了和39一样
class Solution {
public:
vector<vector<int> > ans;
vector<int> path;
void backtracking(vector<int>& candidates,int target,int sum,vector<bool> used,int startIndex){
//终止条件
if(sum==target){
ans.push_back(path);
return;
}
for(int i=startIndex;i<candidates.size()&&sum+candidates[i]<=target;i++){
//去同一层使用过的去重
if(i-1>=0&&candidates[i]==candidates[i-1]&&used[i-1]==false) continue;
sum+=candidates[i];
path.push_back(candidates[i]);
used[i]=true;
backtracking(candidates,target,sum,used,i+1);
sum-=candidates[i];
path.pop_back();
used[i]=false;
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<bool> used(candidates.size(), false);
sort(candidates.begin(),candidates.end());
backtracking(candidates,target,0,used,0);
return ans;
}
};