卡特兰数之不一样的二叉搜索树

在前面写斐波那契数列的时候,忽然想起来卡特兰数列,因此特意来重温一下。html

什么是卡特兰数列

首先这里给出它的递推公式  C= C0Cn-1 + C1Cn-2 + ... + Cn-1C0数组

咋一看,看不明白,这就对了,咱来举几个例子:优化

这里咱们先把第一项直接写出来 C0 = 1,那么spa

C1C0C0 = 1 * 1 = 1code

C2C0C1C1C0 = 1  + 1  = 2htm

C3 = C0C2 + C1C1 C2C0 = 2  + 1 + 2 = 5blog

...get

高中数学到此为止,再写得露馅,回到今天的例题。数学

不一样的二叉搜索树

问题:给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?class

例:输入n = 3,则结果等于5。5种二叉搜索树以下:

 

 

 

分析:

这里咱们注意一下二叉搜素树的性质,知足当前节点值大于左节点值,小于右节点值的二叉树才是二叉搜索树。

假设n个节点的二叉树搜索树的个数是Gn,以 i(1 <= i <= n) 为根节点的二叉搜索树个数定义为Fi

Gn FFF+ ... + Fn

根据搜索树性质,则当根节点的值为i时, 它的左子树为由 节点1 到 节点i-1 组成的二叉搜索树,右子树为由 节点i + 1 到 节点n 组成的二叉搜素树。

推到出: F= Gi-1 Gn-i

那么 GG0Gn-1 G1Gn-2 G2Gn-3 + ... + Gn-1G0

原来G就是卡塔兰数!

 

实现:

这里用的是DP,先计算G,再计算G,一直到Gn。 

 1 int CatalanNum(int n) {
 2     if(n <= 1){
 3         return 1;
 4     }
 5     int[] dp = new int[n + 1];
 6     dp[0] = 1;
 7     dp[1] = 1;
 8     for(int i = 2; i <= n; i++){
 9         for(int j = 1; j <= i; j++){
10             dp[i] += dp[j - 1] * dp[i - j];
11         }
12     }
13     return dp[n];
14 }

时间复杂度:(2 + n) * (n - 1) / 2, 也就是O(N2)。

空间复杂度:dp数组,O(N)。

 

通项公式:

果真,数学家又给出了通项公式:

 

 

 代码实现:

int CatalanNum (int n) {
    if(n == 0){
        return 1;
    }
    int[] dp = new int[n + 1];
    dp[0] = 1;
    for(int i = 0; i < n; i++){
        dp[i + 1] = dp[i] * 2*(2 * i + 1) / (i + 2);
    }
    return dp[n];
}

时间复杂度:(O(N)。

空间复杂度:dp数组,O(N)。(能够优化到O(1), 为何我每次都不优化。。。)

 

最后提醒一下:卡特兰数增加很是快,建议使用大数类型。

 

PS:

最近看到不少简历都提到了Dijkstra,哇塞,真的很亮眼。下次写它。

 

End

相关文章
相关标签/搜索