题目
括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。
说明:解集不能包含重复的子集。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
解题思路
回溯 + 栈
- 根据题意分析可知
- 第一个括号是")",一定无法配对成功
- "(“和”)"的数量一定相同
- 使用回溯方法,得出所有的排列方式
- 使用"栈"帮助检查括号是否可以完全配对
代码
class Solution {
private List<String> list;
public List<String> generateParenthesis(int n) {
char[] parentheses = {'(', ')'};
list = new ArrayList<>();
backtrack(parentheses, new StringBuilder(), n);
return list;
}
private void backtrack(char[] parentheses, StringBuilder sb, int n) {
if (sb.length() == n * 2) {
if (isPair(sb)) list.add(sb.toString());
return;
}
for (char p : parentheses) {
if (!valid(sb, n)) return;
sb.append(p);
backtrack(parentheses, sb, n);
sb.deleteCharAt(sb.length() - 1);
}
}
/**
* 检查基本合法性
*
* @param sb
* @param n
* @return
*/
private boolean valid(StringBuilder sb, int n) {
// 如果第一个是")",无法配对
if (sb.length() > 0 && sb.charAt(0) == ')') return false;
if (sb.length() <= n) return true;
int leftNum = 0, rightNum = 0;
for (int i = 0; i < sb.length(); i++) {
// 如果"("或")"超过半数,无法配对
if (leftNum > n || rightNum > n) return false;
if (sb.charAt(i) == '(') leftNum++;
else rightNum++;
}
return true;
}
/**
* 是否配对
*
* @param sb
* @return
*/
private boolean isPair(StringBuilder sb) {
Deque<Character> stack = new LinkedList<>();
for (int i = 0; i < sb.length(); i++) {
char c = sb.charAt(i);
// 如果栈空 或者 栈顶是")" 或者 当前要入栈的是"("的情况下,入栈
if (stack.isEmpty() || stack.peek() == ')' || c == '(') stack.add(c);
// 要入栈的是")",栈顶是"(",配对成功,将栈顶"("出栈
else if (c == ')') stack.pop();
}
// 如果都配对成功,栈为空
return stack.isEmpty();
}
}