96. Unique Binary Search Trees
       Problem
 Given an integer n, return the number of structurally unique BST’s (binary search trees) which has exactly n nodes of unique values from 1 to n.
 https://leetcode.com/problems/unique-binary-search-trees/
 Example 1:
   Input: n = 3
 Output: 5
 
 Example 2:
  Input: n = 1
 Output: 1
 
 Constraints:
  Test Cases
 | 12
 
 | class Solution:def numTrees(self, n: int) -> int:
 
 | 
solution_test.py| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | import pytest
 from solution import Solution
 from solution2 import Solution as Solution2
 
 
 @pytest.mark.parametrize('n, expected', [
 (3, 5),
 (1, 1),
 
 (5, 42),
 (19, 1767263190),
 ])
 @pytest.mark.parametrize('sol', [Solution(), Solution2()])
 def test_solution(sol, n, expected):
 assert sol.numTrees(n) == expected
 
 | 
  Thoughts
 定义 f(i) 表示 1 到 i 所能组成的二叉搜索树的个数。初值 f(0) = 1,题目所求结果为 f(n)。
 1 到 i 的每个数字都可以作为根节点。假设以 k 作为根节点,那么左边有 k - 1 个节点,共有 f(k - 1) 种 BSTs;右边有 i - k 个节点,共有 f(i - k) 中 BSTs;所以以 k 为根节点的 BST 共有 f(k - 1) * f(i - k) 个。
 所以:
 f(i)=k=1∑i{f(k−1)×f(i−k)}
 时间复杂度 O(n²),空间复杂度 O(n)。
 Code
 solution.py| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | class Solution:def numTrees(self, n: int) -> int:
 dp = [1] * (n + 1)
 for i in range(2, n + 1):
 m = i >> 1
 cnt = 0
 for a in range(m):
 cnt += dp[a] * dp[i - 1 - a]
 cnt <<= 1
 if i & 1:
 cnt += dp[m] * dp[m]
 dp[i] = cnt
 
 return dp[n]
 
 | 
  Math
 卡塔兰数(Catalan number)的数学定义是:
 {C0=1Cn=∑i=1nCi−1Cn−ifor n>0
 显然上边定义的 f(n) 就是卡塔兰数(f(n) = Cₙ),可以用数学方法直接计算。
 f(n)=Cn=n+11(n2n)=(n+1)!n!(2n)!
 本题的 n 不是很大,可以直接用 Python 内置的阶乘函数(math.factorial)计算,时间复杂度 O(n),空间复杂度 O(1)。如果 n 比较大,也可以参考 62. Unique Paths 中的 方法 计算 (n2n)。
 solution2.py| 12
 3
 4
 5
 6
 7
 
 | from math import factorial
 
 class Solution:
 def numTrees(self, n: int) -> int:
 tmp = factorial(n)
 return factorial(n << 1) // tmp // tmp // (n + 1)
 
 |