给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-binary-search-trees
给定一个有序序列1···n,为了构建出一棵二叉搜索树,可以遍历每个数字i,将该数字作为树根,将1··· ( i − 1 ) (i - 1) (i−1)作为左子树,将 ( i + 1 ) ⋅ ⋅ ⋅ n (i + 1)···n (i+1)⋅⋅⋅n序列作为右子树。然后按照相同方式递归构建左子树和右子树。因为构建的每一个二叉树的根节点都不同,所以每棵树都是唯一的。所以原问题可以分解成规模较小的两个子问题,子问题的解可以复用,适合于动态规划问题求解。
定义两个函数:
不同的二叉搜索树的总数 G ( n ) G(n) G(n),是对遍历所有 i ( 1 ≤ i ≤ n ) i(1\le i\le n) i(1≤i≤n)的 F ( i , n ) F(i,n) F(i,n)之和。即:
G ( n ) = ∑ i = 1 n F ( i , n ) G(n)=\sum_{i=1}^{n} F(i, n) G(n)=i=1∑nF(i,n)
对于边界情况,当序列长度为1(只有根)或者为0(空树)时结果为1。
给定序列 1 ⋅ ⋅ ⋅ n 1···n 1⋅⋅⋅n,我们选择数字 i i i作为根,则根为 i i i的所有二叉搜索树的集合是左子树集合和右子树集合的笛卡尔积,对于笛卡尔积中的每个元素,加上根节点之后形成完整的二叉搜索树。
而且 G ( n ) G(n) G(n)和序列的内容是无关的,之和序列的长度有关。故得到:
F ( i , n ) = G ( i − 1 ) ⋅ G ( n − i ) F(i,n)=G(i-1)·G(n-i) F(i,n)=G(i−1)⋅G(n−i)
比如 F ( 3 , 7 ) = G ( 2 ) ⋅ G ( 4 ) F(3,7)=G(2)·G(4) F(3,7)=G(2)⋅G(4)
所以可以得到递归表达式:
G ( n ) = ∑ i = 1 n G ( i − 1 ) ⋅ G ( n − i ) G(n)=\sum_{i=1}^{n} G(i-1) \cdot G(n-i) G(n)=i=1∑nG(i−1)⋅G(n−i)
然后从小到大计算G函数即可。
方法一种推导出的公式 G ( n ) G(n) G(n)在数学上被称为卡塔兰数
C n C_n Cn。其计算公式为:
C 0 = 1 , C n + 1 = 2 ( 2 n + 1 ) n + 2 C n C_{0}=1, \quad C_{n+1}=\frac{2(2 n+1)}{n+2} C_{n} C0=1,Cn+1=n+22(2n+1)Cn
class Solution(object):
def numTrees(self, n):
"""
:type n: int
:rtype: int
"""
res = [0] * (n+1)
res[0], res[1] = 1, 1
for i in range(2, n+1):
for j in range(1, i+1):
res[i] += res[j-1] * res[i-j]
return res[n]
class Solution(object):
def numTrees(self, n):
C = 1
for i in range(0, n):
C = 2*(2*i+1)/(i+2) * C
return int(C)
A u t h o r : C h i e r Author: Chier Author:Chier