LeetCode 热题 HOT 100 第三十六天 96. 不同的二叉搜索树 中等题 用python3求解

题目地址

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

示例 1:在这里插入图片描述
输入:n = 3
输出:5

示例 2:
输入:n = 1
输出:1

提示:
1 <= n <= 19

在这里插入图片描述
二叉查找树(又:二叉搜索树,二叉排序树)
它或者是一棵空树
或者是具有下列性质的二叉树
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树。

本题思路解释
由于 1,2…n 这个数列是递增的,所以我们从任意一个位置“提起”这课树,都满足二叉搜索树的这个条件:左边儿子数小于爸爸数,右边儿子数大于爸爸数

从 1,2,…n 数列构建搜索树,实际上只是一个不断细分的过程
例如,我要用 [1,2,3,4,5,6] 构建
首先,提起 “2” 作为树根,[1]为左子树,[3,4,5,6] 为右子树

现在就变成了一个更小的问题:如何用 [3,4,5,6] 构建搜索树?
比如,我们可以提起 “5” 作为树根,[3,4] 是左子树,[6] 是右子树

现在就变成了一个更更小的问题:如何用 [3,4] 构建搜索树?
那么这里就可以提起 “3” 作为树根,[4] 是右子树
或 “4” 作为树根,[3] 是左子树

可见 n=6 时的问题是可以不断拆分成更小的问题的

假设 f(n)= 我们有 n 个数字时可以构建几种搜索树
我们可以很容易得知几个简单情况 f(0) = 1, f(1) = 1, f(2) = 2
(注:这里的 f(0) 可以理解为 =1 也可以理解为 =0,这个不重要,我们这里理解为 =1,即没有数字时只有一种情况,就是空的情况)

那 n=3 时呢?
我们来看 [1,2,3]
如果提起 1 作为树根,左边有f(0)种情况,右边 f(2) 种情况,左右搭配一共有 f(0)*f(2) 种情况
如果提起 2 作为树根,左边有f(1)种情况,右边 f(1) 种情况,左右搭配一共有 f(1)*f(1) 种情况
如果提起 3 作为树根,左边有f(2)种情况,右边 f(0) 种情况,左右搭配一共有 f(2)*f(0) 种情况
容易得知 f(3) = f(0)*f(2) + f(1)*f(1) + f(2)*f(0)

同理,
f(4)f(4) = f(0)f(0)*f(3)f(3) + f(1)f(1)*f(2)f(2) + f(2)f(2)*f(1)f(1) + f4(3)f4(3)*f(0)f(0)
f(5)f(5) = f(0)f(0)*f(4)f(4) + f(1)f(1)*f(3)f(3) + f(2)f(2)*f(2)f(2) + f(3)f(3)*f(1)f(1) + f(4)f(4)*f(0)f(0)

发现了咩?
对于每一个 n,其式子都是有规律的
每一项两个 f() 的数字加起来都等于 n-1

既然我们已知 f(0)=1, f(1)=1
那么就可以先算出 f(2),再算出 f(3),然后 f(4) 也可以算了…
计算过程中可以把这些存起来,方便随时使用
最后得到的 f(n) 就是我们需要的解了

代码实现(记):

class Solution:
    def numTrees(self, n: int) -> int:
        store = [1,1] #f(0),f(1)
        if n <= 1:
            return store[n]
        for m in range(2,n+1):
            s = m-1
            count = 0
            for i in range(m):
                count += store[i]*store[s-i]
            store.append(count)
        return store[n]

动态规划形式:

class Solution:
    def numTrees(self, n: int) -> int:
        dp = [0] * (n + 1)
        dp[0], dp[1] = 1, 1
        for i in range(2, n + 1):
            for j in range(1, i + 1):
                dp[i] += dp[j - 1] * dp[i - j]
        return dp[-1]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值