Given n, how many structurally unique BST's (binary search trees) that store values 1...n?
For example,
Given n = 3, there are a total of 5 unique BST's.
1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 2 / / \ \ 2 1 2 3这道题很显然可以用递归来做。以n=3为例,可以任意指定1~3中某个元素为根结点,然后剩下的左子树和右子树就转化为n=2或者n=1的情形了。
public int numTrees(int n) {
Integer[] memo=new Integer[n+1];
memo[0]=0;
memo[1]=1;
return helper(n, memo);
}
public int helper(int n,Integer[] memo){
if(memo[n]!=null){
return memo[n];
}
int count=0;
for(int i=1;i<=n;i++){//1~n数中选择i作为根节点
int leftNum=i-1;
int rightNum=n-i;
int leftCount=helper(leftNum, memo);
int rightCount=helper(rightNum, memo);
if(leftCount==0){
count+=rightCount;
}
else if(rightCount==0){
count+=leftCount;
}
else{//都不为0
count+= leftCount*rightCount;
}
}
memo[n]=count;
return count;
}
大神表示,你直接初始化memo[0]=1,就不用分leftCount=0,rightCount=0这么多情况了,直接就是leftCount*rightCount了。哎呀,我的锅。
大神用的DP。从小到大来计算,从 DP[0],DP[1] 一直算到 DP[n] 。
/**
* Taking 1~n as root respectively:
* 1 as root: # of trees = F(0) * F(n-1) // F(0) == 1
* 2 as root: # of trees = F(1) * F(n-2)
* 3 as root: # of trees = F(2) * F(n-3)
* ...
* n-1 as root: # of trees = F(n-2) * F(1)
* n as root: # of trees = F(n-1) * F(0)
*
* So, the formulation is:
* F(n) = F(0) * F(n-1) + F(1) * F(n-2) + F(2) * F(n-3) + ... + F(n-2) * F(1) + F(n-1) * F(0)
*/
int numTrees(int n) {
int dp[n+1];
dp[0] = dp[1] = 1;
for (int i=2; i<=n; i++) {
dp[i] = 0;
for (int j=1; j<=i; j++) {
dp[i] += dp[j-1] * dp[i-j];
}
}
return dp[n];
}
另外,还有大神用了一个比较“数学”的解法。f(0)=1, f(1)=1, f(2)=2, f(3)=5....找规律的话这是一个卡特兰数。卡特兰数的前几项是:其前几项为 : 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, ...
令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=0,1,2,...)
而C(2n,n) = 2n*(2n-1)*(2n-2)*...*(2n-n+1) / n!= 2n/n * (2n-1)/(n-1) * (2n-2)/(n-2) *...* (n+1)/1
int numTrees(int n) {
//cantalan树
//C(2n,n)/(n+1)
long long ans =1;
for(int i=n+1;i<=2*n;i++){
ans = ans*i/(i-n);
}
return ans/(n+1);
}
卡特兰数有许多应用:
括号化
矩阵连乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n)种)
出栈次序
常规分析
首先,我们设f(n)=序列个数为n的出栈序列种数。(我们假定,最后出栈的元素为k,显然,k取不同值时的情况是相互独立的,也就是求出每种k最后出栈的情况数后可用加法原则,由于k最后出栈,因此,在k入栈之前,比k小的值均出栈,此处情况有f(k-1)种,而之后比k大的值入栈,且都在k之前出栈,因此有f(n-k)种方式,由于比k小和比k大的值入栈出栈情况是相互独立的,此处可用乘法原则,f(n-k)*f(k-1)种,求和便是Catalan递归式。
凸多边形三角划分
在一个
凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形。任务是键盘上输入凸多边形的边数n,求不同划分的方案数f(n)。比如当n=6时,f(6)=14。
n对括号正确匹配数目
给定n对括号,求括号正确配对的字符串数,例如:
0对括号:[空序列] 1种可能
1对括号:() 1种可能
2对括号:()() (()) 2种可能
3对括号:((())) ()(()) ()()() (())() (()()) 5种可能
那么问题来了,n对括号有多少种正确配对的可能呢?
考虑n对括号时的任意一种配对方案,最后一个右括号有唯一的与之匹配的左括号,于是有唯一的表示A(B),其中A和B也是合法的括号匹配序列
假设S(n)为n对括号的正确配对数目,那么有递推关系S(n)=S(0)S(n-1)+S(1)S(n-2) +...+S(n-1)S(0),显然S(n)是卡特兰数。
n对括号,有多少种组合
n个元素入栈,有多少种出栈顺序
2n边的凸多边形,连接对角线,可以分出三角形的个数
n × n格点中不越过对角线的单调路径的个数
2n个高矮不同的人,站成两排,保证后排对应的人比前排高,每排从左到右越来越高,有多少种排列方式