22. 括号生成 (dfs,剪枝,回溯,StringBuilder)
数字 n
代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例:
输入1:
n = 3
输出1:
["((()))","(()())","(())()","()(())","()()()"]
输入2:
n = 1
输出2:
["()"]
范围:
1 <= n <= 8
对于 n ,每一个结果字符串的长度都等于 2*n
可以用dfs遍历每一个结果字符串,对于不符合要求的结果字符串进行剪枝
代码:
public List<String> generateParenthesis(int n) {
//初始化 List
List<String> list = new ArrayList<String>();
//如果 n=0 返回空 list
if(n==0)return list;
dfs(n,0,"",list);
return list;
}
// 数字n 计数 字符串 结果集
public void dfs(int n,int num,String s,List<String> list){
//如果 长度 = n*2 将结果添加进list,结束
if(s.length() == n*2){
list.add(s);
return;
}
//添加 '(' 或者 ')'
dfs(n, num+1, s + '(', list);
dfs(n, num+1, s + ')', list);
}
以上代码可以遍历出 n 时所有结果
例如 n = 2 时
["((((","((()","(()(","(())","()((","()()","())(","()))",")(((",")(()",")()(",")())","))((","))()",")))(","))))"]
而对于整体 dfs 像一颗二叉树,如图。
接下来只需要对那些不符合要求的进行剪枝即可
例如
第一个以 ')' 开头的 return
')' 比 '(' 多的 return 等
则可以得出以下代码
class Solution {
//主方法
public List<String> generateParenthesis(int n) {
List<String> list = new ArrayList<String>();
if(n==0)return list;
dfs(n,0,0,new StringBuilder(18),list);
return list;
}
//dfs n数 '(' 个数 ')' 个数 字符串 集合
public void dfs(int n,int upper,int close,StringBuilder s,List<String> list){
//如果第一个是以 ')' 开头,直接 return
if(upper==0&&close==1){
return;
}
//如果 ')' 个数比 '(' 个数多,或者 '(' 个数比 n 多,或者 ')' 个数比 n 多
if(upper>n || close>n || close>upper){
return;
}
//长度达到后,添加进集合中并退出递归
if(s.length() == n*2){
list.add(s.toString());
return;
}
//添加 '('
dfs(n, upper+1, close, s.append('('), list);
//回溯时减去最后一位添加的
s.deleteCharAt(s.length()-1);
//添加 ')'
dfs(n, upper, close+1, s.append(')'), list);
//回溯时减去最后一位
s.deleteCharAt(s.length()-1);
}
}
这里使用 StringBuilder 而不使用 String,是因为StringBuilder的效率要比String高。
(在CSDN本题提交中,用StringBuilder执行用时为:0 ms,而String执行用时为:1 ms)
同时也学习了一些 StringBuilder 的方法。
构造方法:
StringBuilder() 无参构造,初始容量为16
StringBuilder(int capacity) 指定初始容量
StringBuilder(String str) 初始内容为指定字符串
方法:
append(char a) 向字符串最后添加值,有stirng,char等方法重载..
charAt(int index) 类似String的charAt()方法
delete(int start,int end) 移出 start(包括) 至 end(不包括)
deleteCharAt(int index) 移出index的字符
length() 获取有内容的长度
在补充几个
substring(int start,int end) 获取 start(包括) 至 end(不包括)
insert(int offset,Object obj) 插入在offset中,类似String
reverse() 反转字符串
trimToSize() 将StringBuffer对象的中存储空间缩⼩到和字符串长度⼀样的长度,减少空间的浪费。
setCharAt() 修改对象中索引值为index位置的字符为新的字符ch