思路:
1.(吐槽)这一题让你生成有效括号,又不告诉你什么是有效括号。那你让我做什么?
那么到底什么是快乐星球(不对,有效括号)?
这个问题的答案,其实就是这题的灵魂了:'('一定要有闭环才行。
=============version 1 只打败了10%的人===========
我一开始也没想很清楚,想着先把所有括号生成出来再说。那么经典的暴力搜索开始:
可以看到我是在最后生成了所有的字串后,再去字串判断是否符合题意(if(deep==2*n){...}的代码块内)。
if(rightCount>leftCount) 这一句其实最开始没想到的,如果我一开始就有这个逻辑,那么代码当然可以优化。即这一题的第二个考点:剪枝。
class Solution {
public List<String> generateParenthesis(int n) {
if(n == 0) {
return new ArrayList<String>();
}
StringBuilder sb = new StringBuilder();
List<String> resList = new ArrayList<>();
dfs(0,sb,n,resList);
return resList;
}
void dfs(int deep,StringBuilder sb,int n,List<String> resList) {
if(deep == 2*n) {
//比对答案了
int leftCount = 0;
int rightCount = 0;
for(int i=0,len = sb.length();i<len;i++) {
if(sb.charAt(i) == '(')
leftCount++;
else
rightCount++;
// 这个是调试过程中得出的结论
if(rightCount>leftCount) {
break;
}
// 正确答案
if(i == len-1 && leftCount == rightCount) {
resList.add(sb.toString());
}
}
return;
}
sb.append('(');
dfs(deep+1,sb,n,resList);
// 开头就剪枝收益很大
if(deep != 0) {
sb.deleteCharAt(sb.length()-1);
sb.append(')');
dfs(deep+1,sb,n,resList);
sb.deleteCharAt(sb.length()-1);
}
}
}
=============version 2 打败了97%的人===========
有了刚才的经验,我们知道,在dfs搜索的过程中,其实是可以提前剪枝的。
当我们发现sb中 ')' 的数目大于 '(' 的数目,就可以不用往下进行dfs搜索了。
代码如下(我在dfs函数中加了两个参数:leftCount和rightCount):
class Solution {
public List<String> generateParenthesis(int n) {
if(n == 0) {
return new ArrayList<String>();
}
StringBuilder sb = new StringBuilder();
List<String> resList = new ArrayList<>();
dfs(0,sb,n,resList,0,0);
return resList;
}
void dfs(int deep,StringBuilder sb,int n,List<String> resList,int leftCount,int rightCount) {
if(deep == 2*n) {
// 正确答案
if(leftCount == rightCount) {
resList.add(sb.toString());
}
return;
}
if(rightCount > leftCount){
return;
}
sb.append('(');
dfs(deep+1,sb,n,resList,leftCount+1,rightCount);
sb.deleteCharAt(sb.length()-1);
sb.append(')');
dfs(deep+1,sb,n,resList,leftCount,rightCount+1);
sb.deleteCharAt(sb.length()-1);
return;
}
}