一、题目描述
给你一个整数 n
,求恰由 n
个节点组成且节点值从 1
到 n
互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例 1
输入:n = 3
输出:5
示例 2
输入:n = 1
输出:1
提示:1 <= n <= 19
二、代码
代码如下:
class Solution:
def numTrees(self, n: int) -> int:
result = [1, 1] # n=0时 有1种情况, n=1时,也只有1种情况
if n <= 1:
return result[n]
for m in range(2, n + 1):
s = m - 1
count = 0
for i in range(m):
count += result[i] * result[s - i]
result.append(count)
print(result[n])
return result[n]
三、解题思路
本题需要找到所有可能的二叉搜索树的总个数,提供的二叉树结点是长度为n的连续自然数数组,我们希望能找到n取不同值时二叉搜索树总数,找到他们之间的一个规律,现本题解将发现规律进行展示:
我们假设f(n)为长度为n的连续自然数数组对应的二叉搜索树的总个数,则f(n)可以表示为:
先从最基础的情况开始看,
我们不难理解n=0(即空树)、n=1时二叉搜索树可能的情况只可能是1种(即f(0)=1,f(1)=1)
在n=2时我们也能很快知道二叉搜索树可能的情况只有2种(即f(2)=2)
当n=3时,我们可以选择任意的点作为根节点,然后在根节点左边的数被拿去构造左子树,在根节点右边的数被拿去构造右子树;
例如:n=3 时的数组为[1,2,3],
我们此时拿1作为根节点,则根节点左边的数[]拿去构造左子树,根节点右边的数[2,3]拿去构造右子树
此时左边的数[]长度为0,它只可能有1种情况,即f(0)=1;
而右边的数[2,3]长度为2,它则有可能有2种情况,即f(2)=2,
此时我们就可以用上之前求出来的基础结果了,因为左子树的构建和右子树的构建是独立互不影响的,所以他们所可能组成的结果总数为 f(0)f(2) = 2种
当然,因为我们是随机选择某个数作为根节点,所以还可能存在根节点为2,3的情况,以2为根节点为例,此时左边的数为[1],右边的数为[3],我们分别用它们去构建左、右子树,
此时左边的数[1]长度为1,它只可能有1种情况,即f(1)=1;
而右边的数[3]长度为1,它则有可能有1种情况,即f(1)=1;
则当根节点为2时,可能构成的结果数量为 f(1)*f(1) = 1种
同理,当我们选择3作为根节点时,可能构成的结果为 f(2)*f(0) = 2种
当我们加上以上所有结果后,我们就能知道n=3时的结果:
f(3) = f(0)f(2) + f(1)f(1) + f(2)f(0) = 2 + 1 + 2 = 5种
相同的,我们要求n=4时二叉搜索树的总数:
f(4) = f(0)f(3) + f(1)f(2) + f(2)f(1) + f(3)f(0) = 5 + 2 + 2 + 5 = 14种
…
所以当长度为n时,公式如下:
f(n) = f(0)*f(n-1) + f(1)*f(n-2) + f(2)*f(n-3) +… + f(n-3)*f(2) + f(n-2)*f(1) + f(n-1)*f(0)
最后化简就是我们求得的公式。
这样我们就可以从头开始慢慢计算后面的结果,每一次都会用上之前求得的答案。