22.数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”]
示例 2:
输入:n = 1
输出:[“()”]
())
无论之后怎么加括号最后都是无效组合,生成的过程不难想到用回溯法,在每一位尝试放左括号或者右括号,在前一步的基础上继续各自递归尝试,很像二叉树遍历,基本上套用回溯模版即可 private void backtrack("原始参数") {
//终止条件(递归必须要有终止条件)
if ("终止条件") {
//一些逻辑操作(可有可无,视情况而定)
return;
}
for (int i = "for循环开始的参数"; i < "for循环结束的参数"; i++) {
//一些逻辑操作(可有可无,视情况而定)
//做出选择
//递归
backtrack("新的参数");
//一些逻辑操作(可有可无,视情况而定)
//撤销选择
}
}
List<String> res = new ArrayList<>();
public List<String> generateParenthesis(int n) {
dfs(n, n, "");
return res;
}
// left:能放的左括号数量,right 同理
// str:当前生成的字符串
public void dfs(int left, int right, String str){
// 说明此时右括号数量多余左括号,直接舍弃
if(left>right)return;
// 左右括号都用完就记录该组合
if(left==0 && right == 0){
res.add(str);
return;
}
// 左括号用完就继续加右括号,以下同理
if(left==0)dfs(left,right-1,str+")");
else if(right==0)dfs(left-1,right,str+"(");
else{
dfs(left-1,right,str+"(");
dfs(left,right-1,str+")");
}
}
public void dfs(int left, int right, String str){
// 左括号都用到负数了肯定不行了
// 右括号更多必定无效组合
// 并且如果通过了以下两个条件,就说明 right 也 >=0,所以不需要再判断 right
if(left<0 || left>right)return;
if(left==0 && right == 0){
res.add(str);
return;
}
dfs(left-1,right,str+"(");
dfs(left,right-1,str+")");
}
dp[i] = "(" + dp[m] + ")" + dp[k], m + k = i-1
。具体写的时候,这里比较绕的就是 dp[i] 是一个 list,比如 dp[1] = ["()"]
,dp[2]=["()()", "(())"]
,所以即使知道知道动态规划方程, dp 部分还是比较难理解dp[i] = "(" + dp[m] + ")" + dp[k]
的理解:这里的意思其实是 dp[m] 中每个组合和 dp[k] 中每个组合,结合成新的结果。比如 "(" + dp[m] + ")" + dp[k]
先简化理解成 dp[m]+dp[k]
,假设 dp[m]=[1,2], dp[k]=[3,4]
,那么其实得到结果应该为 [13,14,23,24]
。 所以核心部分如下: for (int m = 0; m < i; m++) {
int k = i - 1 - m;
List<String> str1 = dp[m];
List<String> str2 = dp[k];
for (String s1 : str1) {
for (String s2 : str2) {
cur.add("(" + s1 + ")" + s2);
}
}
}
dp[0]= ""
,所以最终代码如下 public List<String> generateParenthesis(int n) {
// 初始化 [[""]],不然 dp[i-1] 都没东西
List<String>[] dp = new List[n + 1];
List<String> dp0 = new ArrayList<>();
dp0.add("");
dp[0] = dp0;
for (int i = 1; i <= n; i++) {
// 记录 dp[i] 的组合
List<String> cur = new ArrayList<>();
for (int m = 0; m < i; m++) {
int k = i - 1 - m;
List<String> str1 = dp[m];
List<String> str2 = dp[k];
for (String s1 : str1) {
for (String s2 : str2) {
cur.add("(" + s1 + ")" + s2);
}
}
}
dp[i] = cur;
}
return dp[n];
}
public static List<String> generateParenthesis(int n) {
List<String> list = new ArrayList<>();
if (n == 0) {//边界条件的判断
list.add("");
return list;
}
for (int m = 0; m < n; m++) {
int k = n - m - 1;
List<String> first = generateParenthesis(m);
List<String> second = generateParenthesis(k);
for (String left : first) {
for (String right : second) {
list.add("(" + left + ")" + right);
}
}
}
return list;
}