回溯要理清思路就是画树状图,然后分析如何去重剪枝!!
回溯思路看这里,非常清晰详细!
代码里要设置begin就是为了避免重复,进行去重剪枝,比方说假如不设置begin就会出现[1,2,3]和[1,3,2]的情况,设置begin就是为了保证接下来加入的每个数字都是大于等于begin的,见下图:
需要排序版本:
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
int len=candidates.size();
vector<vector<int>> res;
if(len==0){
return res;
}
vector<int> path;
sort(candidates.begin(),candidates.end()); // 按升序排序,若不排序会导致一个较大的值在前面然后“target-candidates[i]”就会<0,然后break退出循环从而漏了一部分情况
dfs(candidates,0,len,target,path,res);
return res;
}
void dfs(vector<int>& candidates,int begin,int len, int target,vector<int>& path, vector<vector<int>>&res){
if(target==0){
res.push_back(path); // 表明可以成为一组,push进res数组
}
for(int i=begin;i<len;i++){ // i从begin开始是为了剪枝,避免重复情况
if(target-candidates[i]<0){ // 代表这个candidates[i]不能作为组合内元素
break;
}
path.push_back(candidates[i]);
dfs(candidates,i,len,target-candidates[i],path,res);
path.pop_back(); // 一个回溯函数执行完毕就pop出最上面刚加进来的元素
}
}
};
不排序版本:
则需要把target<0放到循环外判断,若<0则直接return
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
int len=candidates.size();
vector<vector<int>> res;
if(len==0){
return res;
}
vector<int> path;
// sort(candidates.begin(),candidates.end()); // 按升序排序,若不排序会导致一个较大的值在前面然后“target-candidates[i]”就会<0,然后break退出循环从而漏了一部分情况
dfs(candidates,0,len,target,path,res);
return res;
}
void dfs(vector<int>& candidates,int begin,int len, int target,vector<int>& path, vector<vector<int>>&res){
if (target < 0){
return;
}
if(target==0){
res.push_back(path); // 表明可以成为一组,push进res数组
}
for(int i=begin;i<len;i++){ // i从begin开始是为了剪枝,避免重复情况
// if(target-candidates[i]<0){ // 代表这个candidates[i]不能作为组合内元素
// break;
// }
path.push_back(candidates[i]);
dfs(candidates,i,len,target-candidates[i],path,res);
path.pop_back(); // 一个回溯函数执行完毕就pop出最上面刚加进来的元素
}
}
};