Description
給定整數 n,回傳由 1 到 n 組成的所有結構不同的 BST 數量。
Example:
Input: n = 3 Output: 5
Intuition#
選定根節點後,左右子樹的組合數相乘;遍歷所有可能的根就是卡塔蘭數。
- 以 i 為根時,左子樹有 i-1 個節點,右子樹有 n-i 個節點
- 左右子樹的結構數量相互獨立,所以相乘
- G(n) = sum(G(i-1) * G(n-i)) for i in 1..n,這就是卡塔蘭數
Approaches#
1: DP#
- 概念: 自底向上計算 G(0) 到 G(n),G(n) = sum(G(i-1) * G(n-i))
- 時間複雜度:
O(n^2) - 空間複雜度:
O(n)
class Solution {
fun numTrees(n: Int): Int {
val dp = IntArray(n + 1)
dp[0] = 1
dp[1] = 1
for (i in 2..n) {
for (j in 1..i) {
dp[i] += dp[j - 1] * dp[i - j]
}
}
return dp[n]
}
}⭐ 2: 卡塔蘭數公式#
- 概念: 直接用卡塔蘭數的遞推公式 C(n) = C(n-1) * 2(2n-1) / (n+1)
- 時間複雜度:
O(n) - 空間複雜度:
O(1)
class Solution {
fun numTrees(n: Int): Int {
var catalan = 1L
for (i in 1 until n) {
catalan = catalan * 2 * (2 * i + 1) / (i + 2)
}
return catalan.toInt()
}
}卡塔蘭數的常見應用
卡塔蘭數 C(n) 出現在很多組合問題中:
- n 個節點的不同 BST 結構數
- n 對括號的合法組合數
- n+1 個矩陣連乘的不同括號化方式
- 從 (0,0) 到 (n,n) 不越過對角線的路徑數
🔑 Takeaways#
- Pattern: BST 計數問題 = 卡塔蘭數,核心是根的選擇將問題分解為左右獨立子問題
- 關鍵技巧: DP 解法直觀易懂,公式解法效率更高但需要記住卡塔蘭數遞推式