Generate Parentheses
Givennpairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, givenn= 3, a solution set is:
"((()))", "(()())", "(())()", "()(())", "()()()"
原创地址:http://blog.csdn.net/kenden23/article/details/16951299
此题给人一看就是眼花缭乱的感觉。在纷繁的特征中总结出来规律还真是非常难的。
网上分析实在太少了,令人难以看明白。
所以我在这里分析一下,觉得我分析得不好,或者深度不够的,请多多指教。
以我的思维,我是使用二叉树的思维思考这个算法的,不过最后没能自己成功的写出程序。查了查LeetCode论坛,使用的是递归算法,感觉真是精妙绝伦!因为我考虑这个递归树的时候有两个难点:
1 如何两边同时遍历一棵树?
2 如何剔除不适合的路径?比如最中间的路径是不满足条件的。
到底是什么样的树?构造出这样的概念树,我觉得就好理解很多了。
看看下面我画的树:
顺着路径对称地,比如最左边和最右边,遍历两个路径,就是一个解,除了最中间的不符合要求。所以要遍历这样的概念树,很困难。
下面是程序出处:http://discuss.leetcode.com/questions/203/generate-parentheses
vector<string> generateParenthesis(int n) {
vector<string> ans;
if (n>0) generator(ans, "", 0, 0, n);
return ans;
}
void generator(vector<string> & ans, string s, int l, int r, int n) { // r/l: appearance of ) (
if (l == n) {
ans.push_back(s.append(n-r, ')'));
return;
}
generator(ans, s+'(', l+1, r, n);
if (l>r) generator(ans, s+")", l, r+1, n);
}
逐句看看吧,反正没多少。
if (l == n) {
ans.push_back(s.append(n-r, ')'));
return;
}
这个功能是已经遍历了左边的树,然后这里并不需要遍历右边的树,而是非常巧妙地直接补上右括号“)”就完事了。没做过的话,真是想破头脑都难想出来。
而这样居然神奇地完成一个解了。
generator(ans, s+'(', l+1, r, n);
这句就是遍历左递归树,是先序遍历哦,有人说理解为后序,不对,应该是先序。因为s+'('就是先把"("加进去了,然后到下一层树节点。
左子树递归遍历完了就开始由子树递归遍历:
if (l>r) generator(ans, s+")", l, r+1, n);
右子树都是“)”右括号的,所以s+")"代表遍历右子树。
不过令人头痛的就是怎么理解if(l>r)这个条件?
看了些博客说理解为不能让右括号多于左括号,有一定道理,那为什么前面遍历左子树的时候,就是填写左括号“(”的时候,不添加一个判断左子树不能大于右子树的条件呢?所以这样理解好像不大合理。
我的理解,这句正是剔除中间不符合条件的路径的巧妙句子。
因为只有左子树的最右边的子树才会可能出现右括号")"大于左括号"("的情况的,所以这个条件真是"黄娟! 幼妇! 外孙"!