leetcode-96

96. 不同的二叉搜索树

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

image-20210523150610425

背景知识

二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。是数据结构中的一类。在一般情况下,查询效率比链表结构要高。定义如下:

一棵空树,或者是具有下列性质的二叉树

  • 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 左、右子树也分别为二叉排序树;

官方题解(动态规划

给定一个有序序列$1 \cdots n1⋯n$,为了构建出一棵二叉搜索树,我们可以遍历每个数字$i$,将该数字作为树根,将 $1 \cdots (i-1)$ 序列作为左子树,将 $(i+1) \cdots n$ 序列作为右子树。接着我们可以按照同样的方式递归构建左子树和右子树。

在上述构建的过程中,由于根的值不同,因此我们能保证每棵二叉搜索树是唯一的。

由此可见,原问题可以分解成规模较小的两个子问题,且子问题的解可以复用。因此,我们可以想到使用动态规划来求解本题。

在上述构建的过程中,由于根的值不同,因此我们能保证每棵二叉搜索树是唯一的。

由此可见,原问题可以分解成规模较小的两个子问题,且子问题的解可以复用。因此,我们可以想到使用动态规划来求解本题。

算法

题目要求是计算不同二叉搜索树的个数。为此,我们可以定义两个函数:

  1. $G(n)$:长度为 $n$ 的序列能构成的不同二叉搜索树的个数。
  2. $F(i,n)$:以$i$为根、序列长度为$n$的不同二叉搜索树个数$ (1 \leq i \leq n)$。

$G(n)$是需要求解的函数。

根据上一节中的思路,不同的二叉搜索树的总数$G(n)$,是对遍历所有$i(i\leq i\leq n)$的$F(i,n)$之和。既:
$$
G ( n ) = \sum _ { i = 1 } ^ { n } F ( i , n ) \tag{1}
$$
对于边界情况,当序列长度为 1(只有根)或为 0(空树)时,只有一种情况,即:
$$
G ( 0 ) = 1 , \quad G ( 1 ) = 1
$$
给定序列 $1 \cdots n$,我们选择数字$i$作为根,则根为$i$的所有二叉搜索树的集合是左子树集合和右子树集合的笛卡尔积,对于笛卡尔积中的每个元素,加上根节点之后形成完整的二叉搜索树,如下图所示:

image-20210523155137047

举例而言,创建以 $3$为根、长度为$7$ 的不同二叉搜索树,整个序列是$1,2,3,4,5,6,7$,我们需要从左子序列 $1,2$ 构建左子树,从右子序列$4,5,6,7$ 构建右子树,然后将它们组合(即笛卡尔积)。

对于这个例子,不同二叉搜索树的个数为$F(3,7)$。然后将$[1,2]$构建不同左子树的数量表示为$G(2)$,从$[4,5,6,7]$构建不同右子树的数量表示为$G(4)$,注意到$G(n)$和序列的内容无关,只和序列的长度有关。于是,$F(3,7)=G(2)\cdot G(4)$。故可以得到以下公式:
$$
F ( i , n ) = G ( i - 1 ) \cdot G ( n - i ) \tag{2}
$$
结合式(1)(2),可以得到$G(n)$的表达式:
$$
G ( n ) = \sum _ { i = 1 } ^ { n } G ( i - 1 ) \cdot G ( n - i ) \tag{3}
$$
至此,我们从小到大计算$G$函数即可,因为$G(n)$的值依赖于$G(0),\dots,G(n-1)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
def numTrees(self, n):
"""
:type n: int,长度
:rtype: int
"""
G = [0]*(n+1)
G[0], G[1] = 1, 1

# 计算不同长度的
for i in range(2, n+1):
# 按顺序作为根
for j in range(1, i+1):
G[i] += G[j-1] * G[i-j]

return G[n]
作者

bd160jbgm

发布于

2021-05-23

更新于

2021-05-24

许可协议