题目描述
// 22. 括号生成
// 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且
// 有效的 括号组合。
题解
// 回溯搜索法
//
// 想到方法不难,难的是如何设定左右括号添加的关系,特别是什么时候加(停止加)右括号。
// 初始化答案保存位res,特殊情况判断,如果n为0。直接返回空res。
// 定义一个StringBuilder cur,用来保存组合出来的String括号排列,
// 递归调用回溯搜索函数backtrack。最后返回res。
//
// 定义回溯搜索函数backtrack,输入为括号排列保存参数cur,左括号出现次数left,
// 右括号出现次数right,括号排列总组数max(max为常数n,表示总共有n对括号),
// 所以每个排列结果的长度一定为max * 2。
// 定义递归终止条件,如果cur排列的长度等于max * 2,将StringBuilder转为字符串存入
// res中,并返回(回溯)。
// if条件判断:如果左括号出现次数left小于max,将一个左括号填入cur,递归调用
// backtrack,此时函数输入的left变为left+1,即左括号出现次数计数一次。
// 回溯之后的下一句需要删掉cur的末端括号字符,用来回溯排列其他情况。
// 第二个if条件判断关于右括号:和左括号不同,右括号必须和左括号成双成对出现,
// 因此if触发条件为:右括号出现次数如果小于左括号出现次数 right < left,
// 将一个右括号填入cur中,并递归调动backtrack,函数输入的right为right+1,
// 回溯后的下一句为将cur的末端括号字符删除一个,用来回溯排列其他情况。
//
// 执行用时:1 ms, 在所有 Java 提交中击败了96.38%的用户
// 内存消耗:38.5 MB, 在所有 Java 提交中击败了77.08%的用户
import java.util.ArrayList;
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
if (n == 0)
return res;
StringBuilder cur = new StringBuilder();
backtrack(cur, 0, 0, n);
return res;
}
private void backtrack(StringBuilder cur, int left, int right, int max) {
if (cur.length() == max * 2) {
res.add(cur.toString());
return;
}
if (left < max) {
cur.append("(");
backtrack(cur, left + 1, right, max);
cur.delete(cur.length() - 1, cur.length());
}
if (right < left) {
cur.append(")");
backtrack(cur, left, right + 1, max);
cur.delete(cur.length() - 1, cur.length());
}
}
}
// 优化版本
// 执行用时:1 ms, 在所有 Java 提交中击败了96.38%的用户
// 内存消耗:38.4 MB, 在所有 Java 提交中击败了93.82%的用户
import java.util.ArrayList;
class Solution {
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
if (n == 0)
return res;
backtrack("", 0, 0, n);
return res;
}
private void backtrack(String cur, int left, int right, int max) {
if (cur.length() == max * 2) {
res.add(cur);
return;
}
if (left < max) {
backtrack(cur + "(", left + 1, right, max);
}
if (right < left) {
backtrack(cur + ")", left, right + 1, max);
}
}
}