题外话:回溯其实不难,不要自己吓自己!
报错出错的真相只有一个!凶手就是混乱的逻辑!
回溯问题需要想清楚:
- 子问题是什么:对于这个子问题,你有什么(传递内容)
- 结束条件是什么:如何跳出回溯
- 回溯条件是什么:进入下一个自问题的判断条件是什么
22. Generate Parentheses
https://leetcode.com/problems/generate-parentheses/.
最最最简单的回溯,可以当作模板记。
子问题:给定一串字符串(path),例如现在"(("里包含两个左括号,现在要么结束,要么在后面加内容。
结束条件:
字符串里左右括号的数量(left,right)是不是达到了n:
yes -> 结束,并把得到的字符串添加到==结果(res)==里
no -> 需要继续
现在需要继续了,左括号的数量是否达到n:
yes -> 加右括号
no -> 加左括号(⚠️加左括号的时候需要判断左括号数量(left)是否大于右括号数量(right),因为当path="(())",这时候只能加左括号,right大于left需要直接return)
⚠️注意区分res和path。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> res;
string path="";
dfs(res,path,n,0,0);
return res;
}
void dfs(vector<string>& res,string path,int n,int left,int right){
//stop
if (left==n && right==n){
res.push_back(path);
return;
}
//continue
if (left<n)
dfs(res,path+'(',n,left+1,right);
if (left>right)
dfs(res,path+')',n,left,right+1);
}
};
参考:https://blog.csdn.net/fuxuemingzhu/article/details/79362373.
39. Combination Sum
https://leetcode.com/problems/combination-sum/.
纪念一下差点第一次完整的写出了这类问题,除了有一个地方没注意⚠️:就是dfs()里的path和res都是会一直保持不变了,退回上一个dfs()函数时,path/res不会退回到上一个状态的值(我也不知道我这个奇怪的思想是怎么来的)
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res={};
vector<int> path={};
dfs(candidates,target,res,path);
return res;
}
void dfs(vector<int>& data, int target, vector<vector<int>>& res, vector<int>& path){
int sum = accumulate(path.begin(), path.end(), 0);
int N=data.size();
if (sum==target){
res.push_back(path);
return;
}
else if (sum>target)
return;
else{
for (int i=0;i<N;++i){
path.push_back(data[i]);//每一次退回,path不会退回上一次函数里path的值
vector<int> copy(data.begin()+i,data.end());
dfs(copy,target,res,path);
path.pop_back();//所以需要pop_back!⚠️
}
}
}
};
参考:https://blog.csdn.net/fuxuemingzhu/article/details/79322462.