方法1:
通过dfs,穷举所有的可能,然后判断每一种可能,是否合法。
public static List<String> generateParenthesis(int n) { List<String> ans = new ArrayList<>(); char[] par = new char[2*n]; getAll(par,0,2*n,ans); return ans; } public static void getAll(char[] par,int pos,int len,List<String> ans){ if(pos==len){ if(vaild(par)){ ans.add(new String(par)); } return; } par[pos]='('; getAll(par,pos+1,len,ans); par[pos]=')'; getAll(par,pos+1,len,ans); } public static boolean vaild(char[] par){ int count =0; for(int i=0;i<par.length;i++){ if(count<0) break; if(par[i]=='(') count++; if(par[i]==')') count--; } if(count==0) return true; return false; }
方法2:
我们在dfs的时候,可以改变策略。我们记录左括号个个数和右括号的个数。然后只有当左括号个数<n时,我们添加一个左括号。当右括号个数<左括号时,我们添加右括号。这样我们就只生成了合理的结果。
public static List<String> generateParenthesis(int n) { List<String> ans = new ArrayList<>(); StringBuilder par = new StringBuilder(); getAll(par,0,0,n,ans); return ans; } public static void getAll(StringBuilder par,int left,int right,int len,List<String> ans){ if(par.length()==2*len){ ans.add(par.toString()); return; } if(left<len){ par.append('('); getAll(par,left+1,right,len,ans); par.deleteCharAt(par.length()-1); } if(right<left){ par.append(')'); getAll(par,left,right+1,len,ans); par.deleteCharAt(par.length()-1); } }
我们重点来看一下这个dfs,这里涉及到回溯:
public static void getAll(StringBuilder par,int left,int right,int len,List<String> ans){ if(par.length()==2*len){ ans.add(par.toString()); return; } if(left<len){ ----------------------> a par.append('('); getAll(par,left+1,right,len,ans); par.deleteCharAt(par.length()-1); ------------------->c } if(right<left){ ----------------------->b par.append(')'); getAll(par,left,right+1,len,ans); par.deleteCharAt(par.length()-1); } }
最上面几层:a (
a( a(
a( a( a( ,然后
a( a( a( b) b) b) ,执行到6层深度之后, 碰到第一个return。 ((()))
然后就一直回溯:
a( a( a( c -------> a( a( c[删掉一个左括号] b) a( b) b) 第二个return (()())
然后继续回溯 ,神奇。