力扣刷题Python笔记:不同的二叉搜索树

题目

给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?
力扣刷题Python笔记:不同的二叉搜索树_第1张图片
来源:力扣(LeetCode)

Python解法

第一次接触二叉搜索树,我还以为和二叉树一样,结果发现二叉搜索树有一个额外的条件,那就是:树所有左子节点的数字都比父节点数字小,所有右节点的数字都比父节点数字大。即每个父节点分出来的左子树里,任何一个数字都比这个父节点的数字小;右子树里,任何一个数字都比这个父节点的数字大。

以下思路分析和代码均来自力扣题解。

对于本题,由于二叉搜索树以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]是左子树。

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

那么 n=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(0)*f(3) + f(1)*f(2) + f(2)*f(1) + f(3)*f(0)
f(5) = f(0)*f(4) + f(1)*f(3) + f(2)*f(2) + f(3)*f(1) + f(4)*f(0)

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

既然我们已知f(0) = 1, f(1) = 1,那么就可以先算出f(2),再算出f(3),然后f(4)也可以计算…最后得到的f(n)就是我们需要的结果。

代码如下:

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):
        count = 0
        for i in range(m):
            count += store[i]*store[s-i-1]
        store.append(count)
    return store[-1]

你可能感兴趣的:(力扣python刷题,算法)