[LeetCode]: 22 : Generate Parentheses
题目:
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
"((()))", "(()())", "(())()", "()(())", "()()()"
思路1:动态规划
分析1~3的括号匹配情况:
1 ()
2 ()(),(())
3 ()()(), (())(), (()()), ()(()), ((()))
我们得出:输入N=插入(n-1) + 包含(n-1) 其中:
插入:是向n-1的结果的左右位置插入()
包含:用()将n-1的每个结果包含起来
代码如下:
public ArrayList<String> generateParenthesis( int n ) { if ( n == 0 ) { return(null); } ArrayList<ArrayList<String> > arrTotal = new ArrayList<ArrayList<String> >(); /* Init */ ArrayList<String> arrTemp = new ArrayList<String>(); arrTemp.add( "()" ); if ( n == 1 ) { return(arrTemp); } arrTotal.add( arrTemp ); /* 左右拼接+包含 */ for ( int i = 1; i < n; i++ ) { ArrayList<String> arrResultTemp = new ArrayList<String>(); for ( int j = 0; j < arrTotal.get( i - 1 ).size(); j++ ) { /* 包含 */ String strTemp = "(" + arrTotal.get( i - 1 ).get( j ) + ")"; if ( !arrResultTemp.contains( strTemp ) ) { arrResultTemp.add( strTemp ); } /* 左拼接 */ strTemp = "()" + arrTotal.get( i - 1 ).get( j ); if ( !arrResultTemp.contains( strTemp ) ) { arrResultTemp.add( strTemp ); } /* 右拼接 */ strTemp = arrTotal.get( i - 1 ).get( j ) + "()"; if ( !arrResultTemp.contains( strTemp ) ) { arrResultTemp.add( strTemp ); } } arrTotal.add( arrResultTemp ); } return(arrTotal.get( n - 1 ) ); }
结果:当n=4的时候结果中遗失了:(()) (()) 这种情况。经分析为:“插入”的时候,应该向n-1子集合众的每个元素 “所有最小为n-2的闭合”区域进行“包含”处理
貌似思路不对。
改进,还是采用动态规划思想,当根据n-1的所有集合生成n的集合的时候
先把一个(放在每个n-1对括号组合的开头,然后在每个每一个括号配好对的位置插入一个)
代码如下:
public ArrayList<String> generateParenthesis( int n ) { if ( n == 0 ) { return(null); } ArrayList<ArrayList<String> > arrTotal = new ArrayList<ArrayList<String> >(); /* Init */ ArrayList<String> arrTemp = new ArrayList<String>(); arrTemp.add( "()" ); if ( n == 1 ) { return(arrTemp); } arrTotal.add( arrTemp ); for ( int i = 1; i < n; i++ ) { ArrayList<String> arrResultTemp = new ArrayList<String>(); for ( int j = 0; j < arrTotal.get( i - 1 ).size(); j++ ) { arrResultTemp.add( "()" + arrTotal.get( i - 1 ).get( j ) ); /* 先添加一个下面循环判断不到的情况 */ //System.out.println("--------------------补充 :" + "()"+arrTotal.get(i-1).get(j) );
String strTemp ="("+arrTotal.get(i-1).get(j); //先添加一个( /* 遍历字符串,直到可以加上一个)使得括号闭合 */ int iFlag = 0; int intCounter = 1; while ( intCounter < strTemp.length() ) { if ( strTemp.substring( intCounter, intCounter + 1 ).equals( "(" ) ) { iFlag++; /* (:加一 */ }else{ iFlag--; /* ):减一 */ if ( iFlag == 0 ) /* 满足条件:前面的括号都是闭合的, 补完) */ { //System.out.println("Enter :" + strTemp.substring(0,intCounter+1) ); */ String strTempResult = strTemp.substring(0,intCounter+1)+")"+strTemp.substring(intCounter+1); //System.out.println("XXXXXXXXXXXXX :" + strTempResult); arrResultTemp.add( strTempResult ); } } intCounter++; } } arrTotal.add( arrResultTemp ); } return(arrTotal.get( n - 1 ) ); }
思路2:递归+剪枝
用平衡二叉树的构造方法(盗用了网上的图):
- 先构造一个根节点(
- 然后给根节点插入左右孩子,左孩子永远插入(,右孩子永远插入)
- 递归插入,偶数层中的节点包含正确的解
- 在递归的时候,去掉本身就是错误的分支
代码如下:
public static ArrayList<String> BuildAllData(int n,String strInput, ArrayList<String> arrResult) { if(strInput.length() > n*2){ return arrResult; } //Check ( and ) ---------------------------------------------------------------- int iCounter_L= 0; int iCounter_R= 0; //Check ( for(int i =0;i<strInput.length();i++){ if(strInput.substring(i, i+1).equals("(")){ iCounter_L++; } if(strInput.substring(i, i+1).equals(")")){ iCounter_R++; } } if(iCounter_L > n){ return arrResult; } if(iCounter_R > n){ return arrResult; } //System.out.println("strInput : "+strInput); //Check () is close if(iCounter_L == iCounter_R && strInput.length() == n*2 && !arrResult.contains(strInput)){ arrResult.add(strInput); //System.out.println(" is OK !"); } arrResult = BuildAllData(n,strInput+"(",arrResult); if(iCounter_L > iCounter_R){ //当左括号的数目大于有括号的数目的时候 才能够添加右括号 arrResult = BuildAllData(n,strInput+")",arrResult); } return arrResult; } public static ArrayList<String> generateParenthesis(int n) { if ( n == 0 ) { return(null); } ArrayList<String> arrResult = new ArrayList<String>(); arrResult = BuildAllData(n,"(",arrResult); return arrResult; }