0096. Unique Binary Search Tree - chasel2361/leetcode GitHub Wiki

Given n, how many structurally unique BST's (binary search trees) that store values 1 ... n?

Example:
Input: 3
Output: 5
Explanation:
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

令這個函式為 f(n)

假設 n = 0:沒得排,所以可能的排法只有一種
f(0) = 1

假設 n = 1:可能的排法只有一種
f(1) = 1

假設 n = 2:根有兩種可能
根 = 1:
左子樹沒東西,其組合數與 n = 0 相同為 f(0)
右子樹只剩下 2 可以放,其組合數與 n = 1 相同為 f(1) 根 = 2:
左子樹只剩下 2 可以放,其組合數與 n = 1 相同為 f(1)
右子樹沒東西,其組合數與 n = 0 相同為 f(0)
f(2) = f(0)*f(1) + f(1)*f(0)

假設 n = 3:根有三種可能
根 = 1:
左子樹沒東西可以放,其組合數與 n = 0 相同為 f(0)
右子樹會是 2, 3 的組合,其組合數為 f(2)
根 = 2:
左子樹有 1 可以放,其組合數為 f(1)
右子樹有 2 可以放,其組合數為 f(1)
根 = 3:
左子樹會是 2, 3 的組合,其組合數為 f(2)
右子樹沒東西可以放,其組合數為 f(0)
f(3) = f(0)*f(2) + f(1)*f(1) + f(2)*f(0)

以此類推可以得知

https://latex.codecogs.com/gif.latex?f%28n%29%3Df%280%29f%28n-1%29+f%281%29f%28n-2%29+...+f%28n-2%29f%281%29+f%28n-1%29f%280%29

按照這個邏輯可以用遞迴法寫出這樣的程式碼

class Solution:
    def numTrees(self, n: int) -> int:
        if n == 0 or n == 1: return 1
        total = 0
        for i in range(n):
            total += self.numTrees(i)*self.numTrees(n - i - 1)
        return total

測試過後答案沒問題,但計算會超出時間限制,所以還需要改進寫法


參考別人的寫法之後,發現可以利用類似費波納契數列的方式來計算,把前面算出來的值都儲存在陣列裡,要計算新值的時候只要取出舊有的值即可,不必重新計算,計算的程式碼如下:

[1] f(n) 公式
[2] 從 i = 1 計算到 i = n

class Solution:
    def numTrees(self, n: int) -> int:
        res = [0] * (n + 1)
        res[0] = 1
    
        for i in range(1, n + 1):  # [2]
            for j in range(i):  # [1]
                res[i] += res[j] * res[i - j - 1]
        return res[n]

這樣計算的時間複雜度是 O(N^2),空間複雜度是 O(N)


這樣的規律在數學上叫做卡塔蘭數,可以表示為:

https://latex.codecogs.com/gif.latex?%5Clarge%20f%28n%29%20%3D%5Cbegin%7Bcases%7D1%20%26%20n%20%3D%200%5C%5C1%20%26%20n%20%3D%201%5C%5Cf%280%29f%28n-1%29+f%281%29f%28n-2%29+...+f%28n-2%29f%281%29+f%28n-1%29f%280%29%20%26%20n%20%3E%201%5Cend%7Bcases%7D

https://latex.codecogs.com/gif.latex?%5Clarge%20f%5Cbig%28n%5Cbig%29%3D%20%5Cfrac%7B%282n%29%21%7D%7B%28n+1%29%21n%21%7D

所以也可以用數學的方式來解