Generate Parentheses

Generate Parentheses

My Submissions
Total Accepted: 57885  Total Submissions: 176392  Difficulty: Medium

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:

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


一.开始打算用动态规划自底向上的算法,也就是第n个的所有括号数,按照左括号开始的数目进行枚举,后面插入需

要补充的括号数,代码,如下,但是忽略了一种情况

分析了下此方法较复杂,放弃。

class Solution {
public:
    vector<string> generateParenthesis(int n) {
		if(!n){ vector<string> ve; return ve;}
        vector<string> * vectors = new vector<string> [n];
		for(int ve = 0; ve < n; ve ++)
		{
			for( int l_num = ve + 1; l_num > 0; l_num --)
			{
				string str_pre;
				for( int il_num = 0; il_num < l_num; il_num ++)
					str_pre.append("(");
				str_pre.append(")");
				int sub_num = ve + 1 - l_num;
				if( !sub_num) //有需要补充的子括号数
				{
					string str = str_pre;
					for( int ir_num = 0; ir_num < l_num -1; ir_num ++)
						str.append(")");
					vectors[ve].push_back(str);
				}else
				{
					//插在内部
					for( vector<string>::iterator ite = vectors[sub_num - 1].begin();ite != vectors[sub_num - 1].end(); ite ++)
					{
						string str = str_pre;
						str.append(*ite);
						for( int ir_num = 0; ir_num < l_num -1; ir_num ++)
							str.append(")");
						vectors[ve].push_back(str);
					}
					//插在外部
					for( int wair_num = 1;wair_num <= l_num - 1; wair_num ++ )
					{
						for( vector<string>::iterator ite = vectors[sub_num - 1].begin();ite != vectors[sub_num - 1].end(); ite ++)
						{
							string str = str_pre;
							for( int ir_num = 0; ir_num < wair_num; ir_num ++)
								str.append(")");
							str.append(*ite);
							for( int ir_num = 0; ir_num < l_num-1-wair_num; ir_num ++)
								str.append(")");
							vectors[ve].push_back(str);
						}
					}
				}
			}
		}
		//释放多余内存
		for(int i = 0; i < n-1; i++)
			vectors[i].clear();
		return vectors[n-1];	
    }
};
二.网上看了某人的算法,所谓的 卡特兰数,代码非常简单,就是建一个二叉树,然后深度搜索,要求每次分支,已经画的左括号数必须大于

右括号数,都画完时返回,代码如下:

class Solution {
public:
    vector<string> generateParenthesis(int n) {
		vector<string> re;
		if(!n)
			return re;
		string str = "";
        generate(re,n,n,str);
		return re;
    }
	void generate(vector<string> &re,int left,int right,string str)
	{
		if( left == 0 && right == 0)
			re.push_back(str);
		if( left > 0)
			generate( re, left - 1, right, str +"(");
		if( right > left && right > 0)
			generate( re, left, right - 1, str + ")");
		return;
	}
};
三.  卡特兰数应用例子:(引用网上例子

入栈出栈顺序问题:给定一个长度为n的不重复数组,求所有可能的入栈出栈顺序。该问题解的个数也是卡特兰数,根据上面的思路,我们也

可以写出一个类似的代码:

  1. void inoutstack(int in,int out,deque<int> &q,stack<int> &s,deque<int> seq,vector<deque<int>> &result)  
  2.     {  
  3.         if(!in&&!out)  
  4.         {  
  5.             result.push_back(q);  
  6.             return;  
  7.         }  
  8.   
  9.         if(in>0)  
  10.         {  
  11.             s.push(seq.front());  
  12.             seq.pop_front();  
  13.             inoutstack(in-1,out,q,s,seq,result);  
  14.             seq.push_front(s.top());  
  15.             s.pop();  
  16.         }  
  17.   
  18.         if(out>0&&in<out)  
  19.         {  
  20.             q.push_back(s.top());  
  21.             s.pop();  
  22.             inoutstack(in,out-1,q,s,seq,result);  
  23.             s.push(q.back());  
  24.             q.pop_back();  
  25.         }  
  26.     }  
上述代码由于采用了栈和队列模仿整个过程,所以显得略微复杂,但是代码的基本结构还是符合一个类似的基本规则:在某一个特定时刻,入
栈的次数大于或者等于出栈的次数。在生成括号的问题中,我们利用一个string来保存结果,由于打印左括号时不影响打印右括号,所以无需复
杂的状态恢复。在入栈出栈顺序问题中,由于两次递归调用共享同一个栈和队列,所以我们需要手动恢复其内容。在恢复时,队列会从头部删
除和添加,所以我们采用了deque,它可以在头部添加和删除元素。queue只能在头部删除元素,所以没有采用。
中文:卡特兰数
  Catalan数是组合数学中一个常出现在各种计数问题中出现的数列。由以比利时的数学家欧仁·查理·
卡塔兰 ( 1814 1894 )命名。
  原理:
  令h(
0 ) = 1 ,h( 1 )= 1 ,catalan数满足递归式:
  h(n)
=  h( 0 ) * h(n - 1 +  h( 1 ) * h(n - 2 +    +  h(n - 1 )h( 0 ) (其中n >= 2 )
  该递推关系的解为:
  h(n)
= C(2n,n) / (n  +   1 ) (n = 1 , 2 , 3 ,)
       另类递归式:  h(n)=((4*n-2)/(n+1))*h(n-1);
  
  前几项为 (OEIS中的数列A000108): 
1 1 2 5 14 42 132 429 1430 4862 16796
58786 208012 742900
2674440 9694845 35357670 129644790 477638700 1767263190 6564120420
24466267020 91482563640 343059613650 1289904147324 4861946401452
应用

  我总结了一下,最典型的四类应用:(实质上却都一样,无非是递归等式的应用,就看你能不能
分解问题写出递归式了)
1 .括号化问题。

  矩阵链乘: P
= a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的
乘积,试问有几种括号化的方案?(h(n)种)
2 .出栈次序问题。

  一个栈(无穷大)的进栈序列为1,
2 , 3 ,..n,有多少个不同的出栈序列 ?
  类似:
  (
1 )有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有
10元钞票,剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票
找零?(将持5元者到达视作将5元入栈,持10元者到达视作使栈中某5元出栈)
  (
2 )在圆上选择2n个点,将这些点成对连接起来,使得所得到的n条线段不相交的方法数。
3 .将多边行划分为三角形问题。

  将一个凸多边形区域分成三角形区域的方法数
?
  类似:一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班
。如果她
  从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?
  类似:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数
?
4 .给顶节点组成二叉树的问题。

  给定N个节点,能构成多少种形状不同的二叉树?
  (一定是二叉树
!
  先去一个点作为顶点,然后左边依次可以取0至N
- 1个相对应的,右边是N - 1到0个,两两配对相乘,
就是h( 0 ) * h(n - 1 +  h( 2 ) * h(n - 2 +    +  h(n - 1 )h( 0 ) = h(n))
  (能构成h(N)个)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值