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:
[ "((()))", "(()())", "(())()", "()(())", "()()()" ]
思考:组合问题,共有6个位置,每个位置上可以是'('或者')',共有2^6=64种组合结果。解法想到的是递归,每一层函数调用负责填充那一层的值。
其中有些是不满足成对性质的,如何合理的剪枝,即根据部分就可以判断基于这个部分的组合一定是不行的。
有如下结论:
如果左边的数目已经小于等于右边的数目,那么不再添加右边,因为添加了右边一定是不满足成对性质的组合。
另外左边的数目和右边数目都要等于n。
通过“如果左边的数目已经小于等于右边的数目,那么不再添加右边”这条规则,可以合理的减少一些不必要的动作。但是是否这样做以后产生的组合一定就是满足成对性质的呢?
程序运行结果显示的答案是这样做之后产生的组合一定是成对的。我试图证明,但并不是很成功,主要用到如下结论。
如果每一个右括号前面的东西都满足左括号的个数大于等于右括号的个数,那么一定是满足成对性质的。
以“(())()”为例,第一个右括号前面是((,满足左括号的个数大于等于右括号的个数。第二个右括号前面是((),也满足。第3个右括号前面是(())(也满足。所以组合出来的一定是满足成对性质的。
这个结论我无法证明,如果可以证明,那么我的程序可以保证每个右括号前面的左括号的数目大于等于右括号的数目,进而组合出来的结果一定是成对性质的。
总结一下上面的论述:1、通过递归解决组合问题;2、通过一些观察合理的剪枝;3、证明程序是一定可以产生正确组合的。
1 class Solution { 2 public: 3 int leftNumber(string str, int len) { 4 int count = 0; 5 for(int i=0; i<len; i++) { 6 if(str[i]-'('==0) count++; 7 } 8 return count; 9 } 10 11 int rightNumber(string str, int len) { 12 int count = 0; 13 for(int i=0; i<len; i++) { 14 if(str[i]-')'==0) count++; 15 } 16 return count; 17 } 18 void recursion(int len, string &comb, vector<string> &res, int n) { 19 20 if(len==2*n) res.push_back(comb); 21 22 if(len==0) { 23 comb[0] = '('; 24 recursion(len+1, comb, res, n); 25 }else { 26 27 if(leftNumber(comb,len)<=n-1) { 28 comb[len] = '('; 29 recursion(len+1, comb, res, n); 30 } 31 32 33 if(leftNumber(comb,len) > rightNumber(comb, len)) { 34 comb[len] = ')'; 35 recursion(len+1, comb, res, n); 36 } 37 } 38 } 39 40 vector<string> generateParenthesis(int n) { 41 vector<string> res; 42 string comb(n*2,'\0'); 43 recursion(0, comb, res, n); 44 return res; 45 } 46 };