题目:
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
思路:
-
递归:求n可以在n-1的答案前面、后面加上一对括号,或者前面加左括号,后面加右括号,但是得注意重复的情况(当答案是”()()()“等类似的情况时,前面加一对括号和后面加一对括号实际上结果是一样的);
-
枚举:n个括号可以看作2n长度的数组,每个元素可以填左括号或者右括号,枚举所有可能的组合,然后筛选出符合条件的排列,有2的2n次方种情况,效率较差;
-
枚举基础上改进:n个括号实际上合法的只可能是n个左括号和n个右括号,所以在填元素的时候记录个数,如果超过n,则没必要继续往下填,能剪掉一些不必要的分支提升效率;或者当右括号的数量超过左括号的数量,则没必要继续了;
-
3点虽然有改进,但整体思路还是在枚举,然后挑选,如果能按照一定的规则填写,填完之后就是满足要求的,那么效率将会更高,这个规则就是:左括号只要不超过n,随时都能填写,右括号则只要不超过左括号的数量,则就能够填写,这样填写出来的string一定能满足要求;虽然时间复杂度没变,但速度快多了;
代码分析:
- 第四种思路代码实现分析:在满足左括号数量不大于n,下一个字符可以是左括号,右括号数量不大于左括号数量的情况下,下一个字符可以是右括号,都满足时,则可以是左括号,也可以是右括号,可以理解为深搜,但树的某些分支是没有的,假定leftCount为已有左括号的数量,rightCount为已有右括号的数量,那么当leftCount < n时需要搜索下一个字符是 “( ” 的分支,当rightCount < leftCount时,需要搜索下一个字符是“ ) ”的分支,如果都满足,则都需要搜索,搜索退出的条件即 左括号,右括号的数量都是n,此时,将结果加入到list即可;按照分析,leftCount和rightCount不可能大于n,但是代码中退出条件还是使用了>= n,以防万一写出bug死循环;另外,涉及到字符串的拼接操作,我使用了StringBuilder,底层为动态数据实现,拼接不会产生过多的中间字符串,虽然写起来不太优雅,但效率和空间占用上比直接传递字符串会更好,这题因为一开始就直到有2n个字符,所以直接用数组来实现效率会更高;
代码实现:
class Solution {
public List<String> generateParenthesis(int n) {
LinkedList<String> list = new LinkedList<>();
StringBuilder sb = new StringBuilder();
generateOne(list,sb,0,0,n);
return list;
}
public void generateOne(List<String> list,StringBuilder sb, int leftCount, int rightCount,int n){
if(leftCount >= n && rightCount >= n){ //搜索结束,保存结果
list.add(sb.toString());
}
if(leftCount < n){ //下一个字符为 ( 的搜索分支
sb.append("(");
generateOne(list,sb,leftCount+1,rightCount,n);
sb.deleteCharAt(sb.length()-1);
}
if(rightCount < leftCount){//下一个字符为 ) 的搜索分支
sb.append(")");
generateOne(list,sb,leftCount,rightCount+1,n);
sb.deleteCharAt(sb.length()-1);
}
}
}