22. 括号生成
题目描述
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
方法1
思路
动态规划的第一步操作:从左往右第一个括号及其内的情况(也就是第一个"("到和它匹配的")"
之间的情况),剩下的就是子问题了
代码实现1
动态规划递归实现
class Solution {
public:
vector<string> generateParenthesis(int n)
{
vector<string> ret;
if(n<1)
return ret;
return generateParenthesisCore(n);
}
vector<string> generateParenthesisCore(int n)
{
if(n == 0)
return {""};
if(n == 1)
return {"()"};
vector<string> ret;
for(int i = 0;i<n;i++)
{
vector<string> in = generateParenthesisCore(i);
vector<string> out = generateParenthesisCore(n-1-i);
for(auto elem1:in)
for(auto elem2:out)
ret.push_back("("+elem1+")"+elem2);
}
return ret;
}
};
代码实现2
动态规划使用额外存储空间实现
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> ret;
if(n<1)
return ret;
unordered_map<int,vector<string>>dp;
dp[0]={""};
dp[1]={"()"};
for(int i = 2;i<=n;i++)
{
vector<string> temp;
for(int j = 0;j<i;j++)
{
for(auto elem1:dp[j])
{
for(auto elem2:dp[i-1-j])
{
temp.push_back("("+elem1+")"+elem2);
}
}
}
dp[i] = temp;
}
return dp[n];
}
};
方法2
思路
n对括号,其实就是枚举2n个位置的放置情况,这里递归函数中的l,r加在一起起的作用类似于index的作用。右括号只能用它前面的左括号抵消(所以此位置放置右括号时必须确保此位置之前的左括号数大于
右括号数),这可以用归纳法来证明(此位置之前出现的所有")"都能匹配抵消掉,由于左括号数大于
右括号数,所以还有剩余的"(",就能和这个位置的")"匹配上)。而左括号只能与后面的右括号匹配,所以对于左括号没有限制条件。此问题每个位置放置的元素有两种可能,不限制重复,只是要注意是否能够满足放置的条件。
代码实现
class Solution {
public:
vector<string> generateParenthesis(int n)
{
vector<string> ret;
if(n < 1)
return ret;
string temp;
generateParenthesisCore(n, n,ret,temp);
return ret;
}
void generateParenthesisCore(int l, int r,vector<string> &ret,string &temp)
{
if(l == 0 && r == 0)//说明左括号和右括号都用完了,即到达末尾了
{
ret.push_back(temp);
return;
}
else
{ //说明还没有到达末尾
//思考当前位置可以放置的所有合法值进行递归遍历
if(l > 0)//思考什么时候此位置可以放置左括号
{
temp.push_back('(');
generateParenthesisCore(l - 1, r,ret,temp);
temp.pop_back();
}
if(r > l)//思考什么时候此位置可以放置右括号
{//(当此位置前的左括号多于右括号时,也就是它前面有左括号能抵消这个放置的右括号)
temp.push_back(')');
generateParenthesisCore(l, r - 1,ret,temp);
temp.pop_back();
}
}
}
};