39.组合总和
思路:candidates中的元素可以无重复备选取,因此回溯函数中下一层回溯时,回溯函数的参数i不+1。剪枝:需要排序,如果sum加上当前candidates值大于target,直接退出循环。
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
int sum=0;
void backtracking(vector<int>&candidates,int target, int startindex)
{
//终止条件
if(sum==target)
{
result.push_back(path);
return;
}
if(sum>target)
{
return;
}
for(int i = startindex;i<candidates.size()&& sum + candidates[i] <= target;i++)//剪枝
{
path.push_back(candidates[i]);
sum+=candidates[i];
backtracking(candidates,target,i);
path.pop_back();
sum-=candidates[i];
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end()); // 需要排序
if(candidates.size()==0)
{
return result;
}
backtracking(candidates,target,0);
return result;
}
};
40.组合总数II
思路:candidates中的每个数字在每个组合中只能使用一次,解集中不能包含重复的组合,因此需要对candidates排序,在回溯中如果当前元素与上一个元素相同,且上一个元素的used=0,说明此时找到的所有组合都为上次循环中找到的组合的子集,因此直接返回。
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
int sum= 0;
void backtracking(vector<int> & candidates,int target,int startindex,vector<bool> used)
{
//终止条件
if(sum==target)
{
result.push_back(path);
return;
}
if(sum>target)
{
return;
}
//单层逻辑
for(int i = startindex;i<candidates.size()&&sum+candidates[i]<=target;i++)
{
if(i>0&&candidates[i-1]==candidates[i]&&used[i-1]==false) //去重,在同一条路径中不能重复使用元素,在不同路径中去重
{
continue;
}
path.push_back(candidates[i]);
sum+=candidates[i];
used[i] = true;
backtracking(candidates,target,i+1,used);//
path.pop_back();
sum-=candidates[i];
used[i]= false;
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
if(candidates.size()==0)
{
return result;
}
sort(candidates.begin(),candidates.end());
vector<bool> used(candidates.size(),false);
backtracking(candidates,target,0,used);
return result;
}
};
131.分割回文串
思路:分割与组合类似,当分割的位置到达字符串的大小时,分割结束,回溯终止。判断字串是否为回文串在单层的逻辑中,如果不是回文串直接continue。
class Solution {
public:
vector<vector<string>> result;
vector<string> path;
bool Judge(string s,int start,int end)
{
for(int i =start,j=end;i<j;i++,j--)
{
if(s[i]!=s[j])
{
return false;
}
}
return true;
}
void backtracking(string s,int startindex)
{
//终止条件
if(startindex==s.size())
{
result.push_back(path);
return;
}
for(int i =startindex;i<s.size();i++)
{
if(Judge(s,startindex,i))
{
string str = s.substr(startindex,i-startindex+1);
path.push_back(str);
}
else
{
continue;
}
backtracking(s,i+1);
path.pop_back();
}
}
vector<vector<string>> partition(string s) {
if(s.size()==0)
{
return result;
}
backtracking(s,0);
return result;
}
};
收获:
根据题目要求,判断循环中下一层的循环函数的参数startindex应该为i还是i+1.
获取s的子字符串可以用s.substr(start,length),第一个参数为起始点,第二个参数为长度。
切割:当切割点为字符串长度时切割结束。切割后的结果是否满足条件在单层逻辑中判断。