力扣P22 括号生成的DFS思路
题干括号生成
思路
这道题用dfs有两种思路,一种是针对总长度,每个位置都进行尝试,由于对左括号有要求,设置变量记录已有字符串中左括号匹配的数量,根据其数量分类回溯。
class Solution {
public:
vector<string> generateParenthesis(int n) {
string path;
vector<string> res;
dfs(n,0,path,res);
return res;
}
void dfs(int n,int leftok,string path,vector<string> &res)
{
if(path.length()==n*2)
{
if(leftok==n&&leftok!=0)
{
res.push_back(path);
return ;
}
return ;//长度已到最长,不合理情况均排除
}
if(path.length()-2*leftok>0)
{
path+=')';已生成的字符串里还有未匹配的左括号,此时既可以填充左括号也可以填充右括号。
dfs(n,leftok+1,path,res);
path=path.substr(0,path.size()-1);
}
path+='(';//已生成字符串里右括号多,只能填左括号
dfs(n,leftok,path,res);
path=path.substr(0,path.size()-1);
}
};
仔细分析便会发现,当已生成的字符串里右括号数量较多时,理应直接return,这也是这段程序速度慢的原因。
第二中思路是记录好已生成字符串里的left和right的个数,作用等同于记录路径path,相当于对之前的程序进行了简化。此时我们只需要考虑left,right和n之间的关系即可。
class Solution {
public:
vector<string> generateParenthesis(int n) {
string path;
vector<string> res;
// dfs(n,0,path,res);
dfs(n,0,0,path,res);
return res;
}
void dfs(int n,int left,int right,string path,vector<string> &res)
{
if(left==n&&right==n) {res.push_back(path);return ;}//这里要注意对lefrright的判断要有序,先判断相等再判断不等的情况,否则可能出现重复
if(left==right) dfs(n,left+1,right,path+'(',res);
if(left>right) //左括号数量较多时,既可以加左括号也可以加右括号
{
if(left<n) dfs(n,left+1,right,path+'(',res);
dfs(n,left,right+1,path+')',res);
}
if(left<right) return;
}
};
事实上,以上程序仍有值得优化的空间,首先就是left和right均要小于n,其次就是右括号数量大于左括号时直接删除分支即可。
更简练的代码如下。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> res;
dfs(res,"",0,0,n);
return res;
}
void dfs(vector<string> &res,string str,int l,int r,int n)
{
if(l>n||r>n||r>l) return ;
if(l==n&&r==n) {res.push_back(str); return ;}
dfs(res,str+'(',l+1,r,n);
dfs(res,str+')',l,r+1,n);
return ;
}
};