四道题的思路都是回溯法,回溯法的思路就是暴力遍历,同时使用剪枝来限制缩小搜索的空间,从而降低复杂度。回溯法核心就是dfs,将问题想象为一个层级的树结构,每递归一次,树的深度就+1. 在同层就是下面代码中func函数的for()结构。 下面三道题我是用统一的结构来编写。
Leetcode39,组合总和1
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> ans;
int i=0,j=candidates.size()-1;
sort(candidates.begin(),candidates.end()); //排序来为后面剪枝做准备
func(res,ans,candidates,target,i);
return res;
}
void func(vector<vector<int>> & res,vector<int>& ans,vector<int>& candidates,int target,int start)
{
// if(target < 0)
// return ;
if(target == 0)
{
res.push_back(ans);
return;
}
for(int i=start;i<candidates.size();i++)
{
if(target-candidates[i]<0) //剪枝操作
break;
ans.push_back(candidates[i]);
func(res,ans,candidates,target-candidates[i],i);
ans.pop_back();
}
}
};
Leetcode40,组合总和2
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> ans;
int i=0,j=candidates.size()-1;
sort(candidates.begin(),candidates.end()); //排序来为后面剪枝做准备
func(res,ans,candidates,target,i,j);
return res;
}
void func(vector<vector<int>> & res,vector<int>& ans,vector<int>& candidates,int target,int start,int end)
{
if(target == 0)
{
res.push_back(ans);
return;
}
for(int i=start;i<=end;i++)
{
if(candidates[i]>target) //剪枝操作
break;
if(i>start && candidates[i]==candidates[i-1]) //剪枝操作
continue;
ans.push_back(candidates[i]);
func(res,ans,candidates,target-candidates[i],i+1,end);
ans.pop_back();
}
}
};
Leetcode216,组合总和3
class Solution {
public:
vector<vector<int>> combinationSum3(int k, int n) {
vector<vector<int>> res;
vector<int> ans;
func(res,ans,k,n,1,0,n);
return res;
}
void func(vector<vector<int>>& res,vector<int>& ans,int k,int n,int start,int level,int target)
{
if(level == k && target == 0)
{
res.push_back(ans);
return;
}
for(int i=start;i<=9;i++)
{
if(target-i<0)
break;
ans.push_back(i);
func(res,ans,k,n,i+1,level+1,target-i);
ans.pop_back();
}
}
};