题目
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
分析
排列组合题首先考虑递归,把f(n)分成三种情况:{"("+f(n-1)+")", "()"+f(n-1), f(n-1)+"()"},但是发现这样漏掉了一些情况,比如n=4时的"(())(())"。
碰壁之后从状态空间考虑。从左往右考虑每个字符的取法。由于括号的总数是不变的,当左括号有剩余时,随时都可以放置左括号,而左括号的数目达到了之后就必须放右括号。而右括号放置时必须保证其之前的左括号数目大于目前的右括号数目。这样就把状态空间表示成了树的形式。而由于树的深度是一定的,为2*n,所以考虑用递归实现其遍历。
实现
class Solution {
public:
vector<string> generateParenthesis(int n) {
if(n==0) return {};
return solve(2*n, 0, n);
}
private:
vector<string> solve(int layer, int ul, int ll){
if(layer==1) return {")"};
vector<string> ans;
vector<string> tmp;
if(ul<=0){
tmp = solve(layer-1, ul+1, ll-1);
for(auto s: tmp){
ans.push_back("("+s);
}
}
else if(ll<=0){
tmp = solve(layer-1, ul-1, ll);
for(auto s: tmp){
ans.push_back(")"+s);
}
}
else{
tmp = solve(layer-1, ul+1, ll-1);
for(auto s: tmp){
ans.push_back("("+s);
}
tmp = solve(layer-1, ul-1, ll);
for(auto s: tmp){
ans.push_back(")"+s);
}
}
return ans;
}
};
思考
虽然我这种解法能行,但是看了别人的解法之后觉得实在是太复杂了,而且不是很快。由于看到的方法实在太优美了,所以忍不住贴上来。
其中的思想总结下就是:
- 使用一个字符串参数表示之前字符的排列信息
- 引用传参,且当到达末尾时再push_back结果
- 减少不必要的if else。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> ans;
addParenthesis(ans, "", n, 0);
return ans;
}
void addParenthesis(vector<string>& ans, string s, int n, int m) {
if (n == 0 && m == 0)
ans.push_back(s);
if (n > 0) addParenthesis(ans, s+"(", n-1, m+1);
if (m > 0) addParenthesis(ans, s+")", n, m-1);
}
};