四道題的思路都是回溯法,回溯法的思路就是暴力遍歷,同時使用剪枝來限制縮小搜索的空間,從而降低複雜度。回溯法核心就是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();
}
}
};