不同的二叉搜索树
难度中等1446
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例 1:
输入:n = 3
输出:5
示例 2:
输入:n = 1
输出:1
思路:
这道题初次看起来确实无从下手。虽然我的脑海里对于某一数目n的节点能快速地闪现出各种各样的排布方式,然而那些都毫无规律和逻辑可言。所以我们对于这道题要做的就是找到正确的拆分逻辑,把看似花样繁多的排布分出类别来。
直接上正确思路:我们给了n个节点,我们必然要拿出一个作为根节点吧。那就是还剩n-1个节点我们要来分配到子节点当中去。那这n-1个节点怎么分配到左右呢?很简单:(0,n-1),(1,n-2),(2,n-3)……(n-1,0),只能分成这么几类。而拿出任何一类出来,比如(0,n-1):对于这n-1个子节点(相当于根节点的子节点全部在它的右子树上了),我们又回到了原问题:“n-1个节点有几种排布方式”。当然,对于根节点的左子树0,肯定是只有1种排布方式了。最后,只要把左子树排布方式数目*(乘以)右子树排布方式数目,就得到了这一类的总数目。
通过描述,可以发现这一题可以用类似递归的方式去做,但递归还需要加上去重,否则会有很高的复杂度。所以我们转化为使用动态规划的方式,自底向上地去生成到结果。
我们定义动态规划数组dp[],dp[n]表示n个节点的二叉搜索树的个数。
代码:
class Solution(object):
def numTrees(self, n):
# 动态规划
# 分析可得:dp(n) = dp(0)*dp(n-1)+dp(1)*(n-2)+...+dp(n-1)*dp(0)
#规定dp[0]=1 f(1)=dp(0)*dp(0),所以这个base case:dp(0)是1
dp=[0]*(n+1)
dp[0]=1
for i in range(1,n+1):
for j in range(i):
dp[i]+=dp[j]*dp[i-j-1] #是+=不是=
return dp[n]
小结:
代码的巧妙之处在于根据dp(n) = dp(0)*dp(n-1)+dp(1)*(n-2)+...+dp(n-1)*dp(0)这一结论通过两层循环写出状态转移方程,实在是有点取巧的感觉。但只要有这一结论,写出状态转移方程就不是难事了。还是老话:一半理解一半记忆地去解决这一问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了