给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/generate-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
动态规划
假设已知由1~i-1
对括号组成的所有有效括号,我们要生成由i
对括号组成的所有括号,有两种操作
"("
+ 由i-1
对括号组成的所有括号串 +")"
- 在区间
[1, i-1]
取一值j
,两边组合:
由j
对括号组成的所有括号串 + 由i-j
对括号组成的所有括号串
二维string数组 dp[i][j] 表示由 i 对括号组成的所有有效括号序列中下标为 j 的那个序列
每次生成完之后用哈希set去重就行了
代码
class Solution {
public:
vector<string> generateParenthesis(int n)
{
vector<string> ans;
vector<vector<string>> dp(n+1);
dp[1].push_back("()");
for(int i=2; i<=n; i++)
{
// 情况1
for(int j=0; j<dp[i-1].size(); j++)
dp[i].push_back("("+dp[i-1][j]+")");
// 枚举终点,将i拆分为j,i-j
for(int j=1; j<=i-1; j++)
{
for(int l=0; l<dp[j].size(); l++)
{
for(int r=0; r<dp[i-j].size(); r++)
{
dp[i].push_back(dp[j][l]+dp[i-j][r]);
dp[i].push_back(dp[i-j][r]+dp[j][l]);
}
}
}
// hashset去重
unordered_set<string> se(dp[i].begin(), dp[i].end());
dp[i].assign(se.begin(), se.end());
}
for(int j=0; j<dp[n].size(); j++)
ans.push_back(dp[n][j]);
return ans;
}
};
回溯+剪枝
对于每个位置,我们有且只有两种放法: 放 ‘(’ 或者 放 ‘)’
那么对每一个位置,我们两种方法都试一下
剪枝思路:使用两个变量l, r
记录之前序列中左括号,右括号的数量
- 如果
l>n 或 r>n 或 r>l
就表示当前序列已经不是合法的了,直接return - 如果
l==n && r==n
说明我们找到了一种合法的方式,更新答案
代码
class Solution {
public:
vector<string> ans;
void dfs(string &s, int l, int r, int n)
{
if(n<l || n<r || r>l) return;
if(l==n && r==n){ans.push_back(s); return;}
s+='('; dfs(s, l+1, r, n); s.pop_back();
s+=')'; dfs(s, l, r+1, n); s.pop_back();
}
vector<string> generateParenthesis(int n)
{
string s = "";
dfs(s, 0, 0, n);
return ans;
}
};