LeetCode Generate Parentheses 深度分析理解

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:

"((()))", "(()())", "(())()", "()(())", "()()()"

 

原创地址:http://blog.csdn.net/kenden23/article/details/16951299

此题给人一看就是眼花缭乱的感觉。在纷繁的特征中总结出来规律还真是非常难的。

网上分析实在太少了,令人难以看明白。

所以我在这里分析一下,觉得我分析得不好,或者深度不够的,请多多指教。

以我的思维,我是使用二叉树的思维思考这个算法的,不过最后没能自己成功的写出程序。查了查LeetCode论坛,使用的是递归算法,感觉真是精妙绝伦!因为我考虑这个递归树的时候有两个难点:

1 如何两边同时遍历一棵树?

2 如何剔除不适合的路径?比如最中间的路径是不满足条件的。

到底是什么样的树?构造出这样的概念树,我觉得就好理解很多了。

看看下面我画的树:

LeetCode Generate Parentheses 深度分析理解_第1张图片

顺着路径对称地,比如最左边和最右边,遍历两个路径,就是一个解,除了最中间的不符合要求。所以要遍历这样的概念树,很困难。

下面是程序出处:http://discuss.leetcode.com/questions/203/generate-parentheses

vector generateParenthesis(int n) {
    vector ans;
    if (n>0) generator(ans, "", 0, 0, n);
    return ans;
}

void generator(vector & 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)这个条件?

看了些博客说理解为不能让右括号多于左括号,有一定道理,那为什么前面遍历左子树的时候,就是填写左括号“(”的时候,不添加一个判断左子树不能大于右子树的条件呢?所以这样理解好像不大合理。

我的理解,这句正是剔除中间不符合条件的路径的巧妙句子。

因为只有左子树的最右边的子树才会可能出现右括号")"大于左括号"("的情况的,所以这个条件真是"黄娟! 幼妇! 外孙"!


2014-1-25 update
 递归回溯法的程序,其实题目并不难,上面的分析我重新看看,使用树的思维分析也可以,不过如果熟悉了,那么还是不需要分析的太麻烦,不过这样分析对思维锻炼很有好处。

本题最难的就是一个条件判断啦,如我重新写了个程序,如下。这个条件就是if (left < right),这是个十分难想出来的条件,最后怎么吃透这个条件呢?

我就是使用实例,反复走几遍,然后就确立了这个条件,这就是根据实例观察其中的规律的能力了。

虽然就是那么一个条件,自己摸索出来,难度还是相当大的。所以本题我觉得因人而异才能确定其难度指数,我觉得相对难度应该达到4.5星级了,不注意的话,面试的时候是很难写出正确的程序的。也许写个差不多的程序是可以的,不过所谓的差不多程序,就是差一点点没正确的程序,说到底就是错误的程序。

 

class Solution {
public:
    vector generateParenthesis(int n) 
	{
		vector rs;
		string s;
		genParenthesis(rs, s, n, n);
		return rs;
	}
	void genParenthesis(vector &rs, string &s, int left, int right)
	{
		if (left==0)
		{
			rs.push_back(s);
			rs.back().append(right, ')');
			return;
		}

		s.push_back('(');
		genParenthesis(rs, s, left-1, right);
		s.pop_back();
		if (left < right)
		{
			s.push_back(')');
			genParenthesis(rs, s, left, right-1);
			s.pop_back();
		}
	}
};

 难度指数: 4.5星级


你可能感兴趣的:(Algorithm算法,算法和数据结构C++实现,LeetCode,Generate,Parentheses,深度理解分析)