0
点赞
收藏
分享

微信扫一扫

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】

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

示例 1:

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】_时间复杂度

 

 

 

输入:n = 3
输出:5

示例 2:

输入:n = 1
输出:1

提示:

  • ​1 <= n <= 19​

【分析】

方法一:动态规划

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

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

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

算法:

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

假设n个节点存在二叉排序树的个数是G(n),令f(i)为以i为根的二叉搜索树的个数,则:

G(n) = f(1) + f(2) + ... + f(n)

那么,当i为根节点时,其左子树节点个数为i - 1个,右子树节点个数n - i个,则:

f(i) = G(i - 1) * G(n - i)

综合以上两个公式可以得到卡特兰数公式(https://baike.baidu.com/item/%E5%8D%A1%E7%89%B9%E5%85%B0%E6%95%B0)

G(n)  = f(1) + f(2) + ... + f(n) 

        = G(0)*G(n-1) + G(1)*G(n-2) + ... + G(n-1)*G(0)

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】_子树_02

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】_时间复杂度_03

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】_子树_04

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】_子树_05

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】_子树_06

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】_子树_07

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】_时间复杂度_08

class Solution:
def numTrees(self, n: int) -> int:
dp = [0]*(n+1) # 这里的dp相当于卡特兰数的变量G
dp[0], dp[1] = 1, 1

for i in range(2, n+1):
for j in range(1, n+1):
dp[i] += dp[j-1] * dp[i-j]
return dp[n]

这里有详细分析:

​​https://leetcode.cn/problems/unique-binary-search-trees/solution/bu-tong-de-er-cha-sou-suo-shu-by-leetcode-solution/​​

时间复杂度:O(n2),其中n表示二叉搜索树的节点个数。dp(n)函数一共有n个值需要求解,每一次求解需要O(n)的时间复杂度,因此总时间复杂度为O(n2)。

空间复杂度:O(n)。我们需要O(n)的空间存储dp数组。

方法二:数学

事实上,我们在方法一中推导出的dp(n)函数的值在数学上被称为卡特兰数Cn。卡特兰数更便于计算的定义如下:

【二叉搜索树】LeetCode 96. 不同的二叉搜索树【中等】_二叉搜索树_09

class Solution:
def numTrees(self, n: int) -> int:
C = 1
for i in range(n):
C = C * 2*(2*i+1) / (i+2)
return int(C)

时间复杂度:O(n),其中n表示二叉搜索树的节点个数。我们只需要循环遍历一次即可。

空间复杂度:O(1),我们只需要常数空间存放若干变量。

 

 

 

 

  天雨虽宽,不润无根之草。 佛门虽广,不渡无缘之人。

举报

相关推荐

0 条评论