卡特蘭數之不一樣的二叉搜索樹

在前面寫斐波那契數列的時候,忽然想起來卡特蘭數列,因此特意來重溫一下。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

相關文章
相關標籤/搜索