括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入:n = 1
输出:["()"]
提示:
1 <= n <= 8
作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/top-interview-questions-medium/xv33m7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这道题没有做出来。看到题解的也没有搞懂他怎么能将所有的情况都考虑到。最后一步一步debug发现了奥妙。
首先 左括号的数量一定是等于右括号的数量的
其次 任意位置的左括号的数量一定是大于右括号的数量的
以3为例:
left++递归了3层函数
当进入第三层后会执行right++的操作 也就是我们的左括号3个加入an,然后在进入递归将右括号加入三次这时候因为left = 3 所以不会进入上面的呢半部分。之后将结果((()))放入容器ans中,会huisu函数,将an删除最后一个元素。关键来了一直减到右括号不存在an后,左括号-1后!这时候left是2。再次进入huisu函数这时候,left是3 但是an中只有“((”这时候在会进入下半部分的函数执行加)的操作。这就是这个算法的流程核心。
讲完算法的核心,如何运作我们来看一下如何想到这个算法。
其思想其实是我们很熟悉的深度优先遍历的算法我们按照
1.首先 左括号的数量一定是等于右括号的数量的
2.其次 任意位置的左括号的数量一定是大于右括号的数量的
基于此规则我们来进行深度优先遍历
基于规则我们将不符合规则的画上红色标记
对于这个算法而言
//伪代码
void dfs(int left,int right,vector<int> a)
{
//递归出口
//首先我们第一次加入括号一定要是左括号的 这是第二条原则
代码部分
dfs(left+1,right,a+'(');//加入左括号
dfs(left,right,a+')');加入右括号
}
因为我们这样就很像一颗二叉树,所以我们可以使用dfs 只用加入递归出口的条件。
class Solution {
public:
string an;
void huisu(int left,int right,int n,vector<string>& ans){
if(an.length() ==n*2){
ans.push_back(an);
}
if(left<n){
an.push_back('(');
huisu(left+1,right,n,ans);
an.pop_back();
}
if(right<left){
an.push_back(')');
huisu(left,right+1,n,ans);
an.pop_back();
}
}
vector<string> generateParenthesis(int n) {
vector<string> ans;
huisu(0,0,n,ans);
return ans;
}
};