题目
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
解答
解法一:回溯法
思路是:通过记录剩下能放的左/右括号数量,来生成合法的序列。
保证递归时条件:
- 左括号的数量 小于 总次数 n ,才有可能添加左括号。
- 右括号的数量 小于 左括号的数量,才有可能添加右括号。
时刻保证上述两个条件,就能保证最后得到的字符串是合法的。
代码一
class Solution {
public List<String> generateParenthesis(int n) {
List<String> res = new ArrayList<>();
backtrace(res, "", 0, 0, n);
return res;
}
private void backtrace(List<String> res, String cur, int open, int close, int max) {
if(cur.length() == max * 2) {
res.add(cur);
return;
}
if(open < max) backtrace(res, cur + "(", open + 1, close, max);
if(close < open) backtrace(res, cur + ")", open, close + 1, max);
}
}
结果
代码还可以再次优化,使用 char[ ] 减少大量的字符串拼接。
优化后代码
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
char[] cur = new char[2 * n];
backtrace(cur, 0, 0, 0, n);
return res;
}
private void backtrace(char[] cur, int index, int open, int close, int max) {
if(open == close && open == max) {
res.add(new String(cur));
return;
}
if(open < max) {
cur[index] = '(';
backtrace(cur, index + 1, open + 1, close, max);
}
if(close < open) {
cur[index] = ')';
backtrace(cur, index + 1, open, close + 1, max);
}
}
}
结果
解法二:动态规划
每一个 c 的位置,都可以确定一部分结果集。
假如有 n 对括号,那么所有匹配的括号只可能在 0 - c 之间或者 0 - c 之外 。
而除了位置 0 和位置 c 组成的括号外,其他部分的括号加起来正好是: a + (n - a - 1) = n - 1 对
这样就可以产生一部分的结果集:【 ( a对的结果集 ) n - a -1 对括号的结果集 】。
对 c 进行迭代,就会得到所有正确匹配括号的结果集了。
代码一:备忘录
class Solution {
Map<Integer, List<String>> memo = new HashMap<>();
public List<String> generateParenthesis(int n) {
if(memo.containsKey(n)) return memo.get(n);
List<String> ans = new ArrayList();
if (n == 0) {
ans.add("");
} else {
for (int c = 0; c < n; ++ c)
for (String left: generateParenthesis(c))
for (String right: generateParenthesis(n - 1 - c))
ans.add("(" + left + ")" + right);
}
memo.put(n, ans);
return ans;
}
}
代码二:自底向上的动态规化
class Solution {
public List<String> generateParenthesis(int n) {
Map<Integer, List<String>> dp = new HashMap<>();
dp.put(0, new ArrayList<>(Arrays.asList("")));
for(int i = 1; i <= n; i ++) {
List<String> cur = new ArrayList<>();
for(int c = 0; c < i; c ++) {
for(String left : dp.get(c)) {
for(String right : dp.get(i - c - 1)) {
cur.add("(" + left + ")" + right);
}
}
}
dp.put(i, cur);
}
return dp.get(n);
}
}