题目
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入:n = 1
输出:["()"]
提示:
- 1 <= n <= 8
解法
解法1 :dp
思路:
当我们清楚所有 i<n 时括号的可能生成排列后,对与 i=n 的情况,我们考虑整个括号排列中最左边的括号。
它一定是一个左括号,那么它可以和它对应的右括号组成一组完整的括号 “( )”,我们认为这一组是相比 n-1 增加进来的括号。
那么,剩下 n-1 组括号有可能在哪呢?
【这里是重点,请着重理解】
剩下的括号要么在这一组新增的括号内部,要么在这一组新增括号的外部(右侧)。
既然知道了 i<n 的情况,那我们就可以对所有情况进行遍历:
“(” + 【i=p时所有括号的排列组合】 + “)” + 【i=q时所有括号的排列组合】
其中 p + q = n-1,且 p q 均为非负整数。
事实上,当上述 p 从 0 取到 n-1,q 从 n-1 取到 0 后,所有情况就遍历完了。
注:上述遍历是没有重复情况出现的,即当 (p1,q1)≠(p2,q2) 时,按上述方式取的括号组合一定不同。
/*
dp[i]:表示i组括号中的所有有效组合
dp[i] = "(dp[p]的所有有效组合)+【dp[q]的组合】",其中 1 + p + q = i , p从0遍历到i-1, q则相应从i-1到0
*/
class Solution {
public:
vector<string> generateParenthesis(int n) {
//简单动态规划
if(n == 0) return {};
if(n == 1) return { "()"};
vector<vector<string>> dp(n+1);
dp[0] = {""};
dp[1] = {"()"};
for(int i = 2; i <= n; i++){
for(int j = 0 ; j < i; j++){
for(string p : dp[j]){
for(string q: dp[i-j-1]){
string str = "(" + p + ")" + q;
dp[i].push_back(str);
}
}
}
}
return dp[n];
}
};
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
笔记
解法2:暴力法
class Solution {
/*暴力法:我们可以生成所有 2^{2n}个 '(' 和 ')' 字符构成的序列,然后我们检查每一个是否有效即可。
思路:为了生成所有序列,我们可以使用递归。长度为 n 的序列就是在长度为 n-1 的序列前加一个 '(' 或 ')'。
为了检查序列是否有效,我们遍历这个序列,并使用一个变量 balance 表示左括号的数量减去右括号的数量。如果在遍历过程中 balance 的值小于零,或者结束时 balance 的值不为零,那么该序列就是无效的,否则它是有效的。
*/
bool valid(const string& str){
int balance = 0;
for(char c: str){
if(c == '('){
balance++;
}else{
balance--;
}
if(balance < 0){ //遍历过程中
return false;
}
}
return balance == 0; //结束时
}
void generate_all(string& current, int n, vector<string>& result){
if(n == current.size()){
if(valid(current)){
result.push_back(current);
}
return;
}
// 递归
current += '(';
generate_all(current,n,result);
current.pop_back();
current += ')';
generate_all(current,n,result);
current.pop_back();
}
public:
vector<string> generateParenthesis(int n) {
vector<string> result;
string current;
generate_all(current,n*2,result);
return result;
}
};