今天看到去年的微软笔试题其中有一道是,进栈出栈的题目,给定1,2,。。。n共n个数,问有多少种不同的出栈次序?
我的第一直觉就是这个东西很熟悉,应该是卡特兰数问题,当然事实上也是如此,下面是更严密的分析:
将每个数的进栈操作标记为状态‘1’,出栈操作标记为状态‘-1’,对于栈来讲,肯定是进栈的次数大于等于出栈的次数(因为不可能还没进去呢就能出来)
于是,就是状态序列中1的个数大于-1的个数的问题,这正是卡特兰数问题,也就是任何时刻所有状态序列中所有标记之和都要大于等于0。
题目一下子变得很简单,结果就是C(2n,n)/(n+1).
下面给出卡特兰数的定义:
令h(1)=1,h(0)=1,catalan数(卡特兰数)满足递归式:
h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (其中n>=2)
另类递归式:
h(n)=((4*n-2)/(n+1))*h(n-1);
该递推关系的解为:
h(n)=C(2n,n)/(n+1) (n=1,2,3,...)
其实卡特兰数是非常有用的一个东西,而且非常有意思,下面举几个常见的例子:
1、给定节点组成二叉树个数有多少?
分析:
当n=1时,只有1个根节点,则只能组成1种形态的二叉树,令n个节点可组成的二叉树数量表示为h(n),则h(1)=1; h(0)=0;
当n=2时,1个根节点固定,还有2-1个节点。这一个节点可以分成(1,0),(0,1)两组。即左边放1个,右边放0个;或者左边放0个,右边放1个。即:h(2)=h(0)*h(1)+h(1)*h(0)=2,则能组成2种形态的二叉树。
当n=3时,1个根节点固定,还有2个节点。这2个节点可以分成(2,0),(1,1),(0,2)3组。即h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=5,则能组成5种形态的二叉树。
以此类推,当n>=2时,可组成的二叉树数量为h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0)种,即符合Catalan数的定义,可直接利用通项公式得出结果。
2、矩阵链乘法问题(加括号问题)(此处只求种类树,不是求最优问题)
分析:给定n个矩阵{A1,A2,...An},其中Ai与Ai+1是可乘的,考查这n个矩阵的乘积A1A2...An,使得所需的数乘次数最少。
设n个矩阵的连乘有不同的计算次序P(n),可以先在第k个和第k+1个矩阵之间讲原矩阵分为两个矩阵子序列,k=1,2,...n-1。然后分别对这两个矩阵子序列完全加括号;
最后对所得的结果加括号,得到原矩阵序列的一个完全加括号,得递归式
n=1 时 P(n)=1;
n>1 时 P(n)=∑ k=1~n-1(P(k)*P(n-k));
P(n)就是卡特兰数这么多种计算次序,如果用穷举法查找数乘次数最小需要P(n)次运算,因此该问题可以用动态规划来求解(这不是本文要叙述的重点)
3、凸多边形三角划分问题(最优解用到动态规划算法,此处只求划分种树)