题目描述:
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例:
输入:n = 3
输出:[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
方法1:动态规划
主要思路:
(1)这道题如果想到思路的,其实挺简单的,主要就是使用已生成的括号组成,来组合成新生成的括号组成;
(2)使用动态数组vector<vector> dp(n+1);其中dp[ i ] 表示当 i 对括号时,可以生成的合法的括号组合,那么对于 dp[ i ] 的组合,可以通过 dp[ j ]和dp[ i-j-1 ] 的组合,再次组合 而成,在合适的位置插入新的 “()” 即可;
(3)直观的想,就是dp[ j ]中的 j 对括号,dp[ i-j-1 ]中的 i-j-i 对括号,再加上新增的 1 个括号,总共就是 i 对括号,现在只需要把他们组成一起即可;
class Solution {
public:
vector<string> generateParenthesis(int n) {
//特殊的情形
if(n==0)
return vector<string>(1,"");
if(n==1)
return vector<string>(1,"()");
//定义的动态数组
vector<vector<string>> dp(n+1);
//初始状态
dp[0]=vector<string>(1,"");
dp[1]=vector<string>(1,"()");
//第一层是 需要确定的新的 括号对数
for(int i=2;i<=n;++i){
//第二层用来辅助确定另外两个需要的子组合
for(int j=0;j<i;++j){
//第一个子组合
for(string& str1:dp[j]){
//第二个子组合
for(string& str2:dp[i-j-1]){
dp[i].push_back("("+str1+")"+str2);//两个子组合和一对括号组成的 i 对括号组合
}
}
}
}
return dp[n];//返回n对括号的组合
}
};
方法2:回溯
主要思路:
(1)回溯的主要思路就是在能做的选择中做选择,到满足要求的时候,存储结果,到不满足要求的时候,提前返回,返回后,记得恢复原始的状态;
(2)这里的选择就是左,右括号,满足的条件是左右括号的数量都减少到0,不满足要求的结果是左边括号数量大于右边的括号数量,或者左边括号数量小于0,或者右边括号数量小于0;
(3)在做选择时,直接将左括号或右括号压入到中间变量str 的结尾,并在返回的时候,弹出即可;
class Solution {
public:
void helper(vector<string>& res,string& str,int& left,int& right){
//不满足要求的情形
if(left>right||left<0||right<0)
return ;
//满足要求的情形
if(!left&&!right){
res.push_back(str);
return ;
}
//选择左括号
str.push_back('(');
--left;
helper(res,str,left,right);
++left;
str.pop_back();//弹出
//压入右括号
str.push_back(')');
--right;
helper(res,str,left,right);
++right;
str.pop_back();//弹出
}
vector<string> generateParenthesis(int n) {
if(n==0)
return vector<string>(1,"");
if(n==1)
return vector<string>(1,"()");
string str;
vector<string> res;
int left=n;
int right=n;
helper(res,str,left,right);
return res;
}
};