【二叉搜索樹】LeetCode 96. 不同的二叉搜索樹【中等】

給你一個整數 n ,求恰由 n 個節點組成且節點值從 1 到 n 互不相同的 二叉搜索樹 有多少種?返回滿足題意的二叉搜索樹的種數。

示例 1:

 

 

 

輸入:n = 3
輸出:5

示例 2:

輸入:n = 1
輸出:1 

提示:

  • 1 <= n <= 19

【分析】

方法一:動態規劃

給定一個有序序列"1...n", 爲了構建出一棵二叉搜索樹,我們可以遍歷每個數字i,將該數字作爲樹根,將1...(i-1)作爲左子樹,將(i+1)...n作爲右子樹。接着我們可以按照同樣的方式遞歸構建左子樹和右子樹。

在上述構建的過程中,由於根的值不同,因此我們能保證每一棵二叉搜索樹爲唯一的。

由此可見,原問題可以分解成兩個規模較小的子問題,且子問題的解可以複用。因此,我們可以想到使用動態規劃來求解本題。

算法:

題目要求是計算不同二叉搜索樹的個數。爲此,我們可以定義兩個函數:

假設n個節點存在二叉排序樹的個數是G(n),令f(i)爲以i爲根的二叉搜索樹的個數,則:

G(n) = f(1) + f(2) + ... + f(n)

那麼,當i爲根節點時,其左子樹節點個數爲i - 1個,右子樹節點個數n - i個,則:

f(i) = G(i - 1) * G(n - i)

綜合以上兩個公式可以得到卡特蘭數公式(https://baike.baidu.com/item/%E5%8D%A1%E7%89%B9%E5%85%B0%E6%95%B0)

G(n)  = f(1) + f(2) + ... + f(n) 

        = G(0)*G(n-1) + G(1)*G(n-2) + ... + G(n-1)*G(0)

class Solution:
    def numTrees(self, n: int) -> int:
        dp = [0]*(n+1) # 這裏的dp相當於卡特蘭數的變量G
        dp[0], dp[1] = 1, 1

        for i in range(2, n+1):
            for j in range(1, n+1):
                dp[i] += dp[j-1] * dp[i-j]
        return dp[n] 

這裏有詳細分析:

https://leetcode.cn/problems/unique-binary-search-trees/solution/bu-tong-de-er-cha-sou-suo-shu-by-leetcode-solution/

時間複雜度:O(n2),其中n表示二叉搜索樹的節點個數。dp(n)函數一共有n個值需要求解,每一次求解需要O(n)的時間複雜度,因此總時間複雜度爲O(n2)。

空間複雜度:O(n)。我們需要O(n)的空間存儲dp數組。

方法二:數學

事實上,我們在方法一中推導出的dp(n)函數的值在數學上被稱爲卡特蘭數Cn。卡特蘭數更便於計算的定義如下:

class Solution:
    def numTrees(self, n: int) -> int:
        C = 1
        for i in range(n):
            C = C * 2*(2*i+1) / (i+2)
        return int(C) 

時間複雜度:O(n),其中n表示二叉搜索樹的節點個數。我們只需要循環遍歷一次即可。

空間複雜度:O(1),我們只需要常數空間存放若干變量。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章