题目链接:https://leetcode-cn.com/problems/generate-parentheses/
题目描述
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
思路
1 暴力法
我们可以生成所有
2
2
n
2^{2n}
22n 个 '('
和 ')'
字符构成的序列。然后,我们将检查每一个是否有效。
为了生成所有序列,我们使用递归。长度为 n
的序列就是 '('
加上所有长度为 n-1
的序列,以及 ')'
加上所有长度为 n-1
的序列。
复杂度分析
- 时间复杂度: O ( 2 2 n n ) O(2^{2n}n) O(22nn),对于 2 2 n 2^{2n} 22n 个序列中的每一个,我们用于建立和验证该序列的复杂度为 O ( n ) O(n) O(n)。
- 空间复杂度: O ( 2 2 n n ) O(2^{2n}n) O(22nn),简单地,每个序列都视作是有效的。请参见 方法三 以获得更严格的渐近界限。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> ret;
if(n<1) return ret;
string s = "";
help(s,n*2,ret);
return ret;
}
private:
void help(string s, int len, vector<string>& ret){
if(s.size() == len){
if(isValid(s))
ret.push_back(s);
return;
}
s.push_back('(');
help(s,len,ret);
s.pop_back();
s.push_back(')');
help(s,len,ret);
s.pop_back();
}
bool isValid(string s){
stack<char> st;
for (auto ch:s){
if(ch == '(')
st.push(ch);
else{
if(st.empty()) return false;
else
st.pop();
}
}
return st.empty();
}
};
上述判断括号是否有效用了栈来实现,实际上可以不用栈,省去额外的空间开销。
bool isValid(string s){
int cnt = 0; // 括号的数量减去右括号的数量的净值
for (auto ch:s){ // 如果这个值始终小于零或者不以零结束,该序列就是无效的,否则它是有效的。
if(ch == '(')
cnt++;
else
cnt--;
if(cnt<0)
return false;
}
return cnt == 0;
}
2 回溯
只有在我们知道序列仍然保持有效时才添加 '('
or ')'
,而不是像 方法一 那样每次添加。我们可以通过跟踪到目前为止放置的左括号和右括号的数目来做到这一点,
如果左括号数量<n,可以放一个左括号。 如果右括号数量小于左括号的数量,可以放一个右括号。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> ret;
if(n<1) return ret;
string s = "";
help(s,0,0,n,ret);
return ret;
}
private:
// left:左括号数量,right:右括号数量
void help(string s,int left, int right, int n, vector<string>& ret){
if(s.size() == n*2){
ret.push_back(s);
return;
}
if(left<n)
help(s+"(", left+1, right,n,ret);
if(right<left)
help(s+")", left, right+1,n, ret);
}
};