解题思路
经典的卡特兰数的实际应用问题,相同数学原理的问题还有:矩阵连乘积问题、凸多边形的三角剖分问题、出栈次序问题、括号匹配问题
首先把卡特兰数的递推式摆这,数学定义请自行百度:
f(0)=1,f(1)=1,n>=2时:
f(n)= f(0) * f(n-1) +
f(1) * f(n-2) +
…
f(n-2) * f(1)
f(n-1) * f(0)
解此递推式得f(n)=C(2n,n)/(n+1)=C(2n,n)-C(2n,n-1)
如果已知递推式,用DP的方法去求f(n)是十分简单的,就好像用DP的方法求斐波那契数列一样,关键是怎么看出来本问题要求的数是卡特兰数来的
以下解释为什么“不同的二叉搜索树的个数”是一个卡特兰数:
设f(n)表示1…n这n个节点的不同二叉搜索树的个数
一、当1为根节点时,左子树为空,右子树上有(n-1)个节点,那么这n-1个节点能组成的不同二叉搜索树就是f(n-1),所以此时的二叉搜索树的总的可能的个数为f(n-1)
二、当i为根节点时(1<i<n),左子树是由1…i-1这(i-1)个节点组成的,那么左子树的可能的二叉搜索树个数为f(i-1);右子树是由i+1…n这(n-i)个节点构成的,那么右子树的可能的二叉搜索树个数为f(n-i),根据组合数学里的乘法原则,此时的二叉搜索树的总的可能的个数为f(i-1)*f(n-i)
三、当n为根节点时,右子树为空,左子树上有(n-1)个节点,所以此时的二叉搜索树的总的可能的个数为f(n-1)
综上,f(n)=f(n-1)+Σ[f(i-1)*f(n-i)]+f(n-1),1<i<n
实际上,空树也是一种二叉搜索树,所以可以定义f(0)=1,
那么上述公式可写成:f(n)=f(0)f(n-1)+Σ[f(i-1)*f(n-i)]+f(n-1)f(0),1<i<n
显然这就是卡特兰数的递推公式
在已知递推公式的前提下,定义表格存储前面已经计算下来的值,用到时直接访问内存,避免递归的重复计算,这就很简单了
class Solution {
public int numTrees(int n) {
if(n<=0) return 1;//空树也是二叉搜索树
//n>=1
int [] dp_Catalan=new int[n+1];//dp[i]就表示i个节点的情况个数
dp_Catalan[0]=1;
dp_Catalan[1]=1;
//初始化卡特兰数前两项
for(int i=2;i<=n;i++){
for(int k=0;k<=i-1;k++){
dp_Catalan[i]+=dp_Catalan[k]*dp_Catalan[i-k-1];//卡特兰
}
}
return dp_Catalan[n];
}
}