当前位置: 首页 > news >正文

【LeetCode】动态规划—96. 不同的二叉搜索树(附完整Python/C++代码)

动态规划—96. 不同的二叉搜索树

  • 题目描述
  • 前言
  • 基本思路
    • 1. 问题定义
    • 2. 理解问题和递推关系
      • 二叉搜索树的性质:
      • 核心思路:
      • 状态定义:
      • 状态转移方程:
      • 边界条件:
    • 3. 解决方法
      • 动态规划方法:
      • 伪代码:
    • 4. 进一步优化
    • 5. 小总结
  • Python代码
      • Python代码解释
  • C++代码
      • C++代码解释
  • 总结

题目描述

在这里插入图片描述

前言

不同的二叉搜索树问题 是一个经典的动态规划问题。给定一个整数 n,我们需要构造出由 n 个节点组成的所有不同的 二叉搜索树(BST)。在这类问题中,我们不仅需要理解二叉搜索树的性质,还需要通过动态规划来计算不同形态的二叉搜索树的数量。


基本思路

1. 问题定义

给定一个整数 n,求由 n 个节点构成的所有不同的二叉搜索树的数量。每个二叉搜索树的节点包含从 1n 的整数,每个整数只能使用一次。

2. 理解问题和递推关系

二叉搜索树的性质:

  • 二叉搜索树(BST)的性质是,对于每个节点:
    • 左子树上所有节点的值都小于该节点的值。
    • 右子树上所有节点的值都大于该节点的值。

核心思路:

如果我们选择节点 i 作为根节点,那么:

  1. 节点 1i-1 会组成根节点 i 的左子树。
  2. 节点 i+1n 会组成根节点 i 的右子树。
  3. 左子树和右子树的组合方式可以递归地进行计算,最终组合成完整的 BST。

状态定义:

dp[i] 表示 i 个节点能构成的不同二叉搜索树的数量。最终我们要求解的是 dp[n]

状态转移方程:

对于每一个根节点 i,它的左子树有 i-1 个节点,右子树有 n-i 个节点。左子树和右子树的组合方式相乘,即:
d p [ i ] = ∑ k = 1 i d p [ k − 1 ] × d p [ i − k ] dp[i] = \sum_{k=1}^{i} dp[k-1] \times dp[i-k] dp[i]=k=1idp[k1]×dp[ik]
其中,dp[k-1] 表示左子树的组合数,dp[i-k] 表示右子树的组合数。

边界条件:

  • n = 0 时,空树也是一种二叉搜索树,因此 dp[0] = 1

3. 解决方法

动态规划方法:

  1. 初始化一个数组 dp,其中 dp[0] = 1,表示空树。
  2. 使用递推公式计算 dp[i],即根据左子树和右子树的组合方式来更新 dp 数组。
  3. 最终 dp[n] 即为 n 个节点构成的不同二叉搜索树的数量。

伪代码:

initialize dp array with dp[0] = 1
for i from 1 to n:for j from 1 to i:dp[i] += dp[j-1] * dp[i-j]
return dp[n]

4. 进一步优化

  • 空间优化:由于每个 dp[i] 只依赖于之前的状态,因此我们已经使用最小的空间来存储这些状态。
  • 时间复杂度:动态规划的时间复杂度为 O(n^2),适合处理中等规模的输入。

5. 小总结

  • 问题思路:通过递归地构建左子树和右子树,利用动态规划的思想,可以高效计算不同二叉搜索树的数量。
  • 核心公式:状态转移方程 dp[i] = \sum_{k=1}^{i} dp[k-1] \times dp[i-k],每次通过左子树和右子树的组合方式进行计算。

以上就是不同的二叉搜索树问题的基本思路。


Python代码

class Solution:def numTrees(self, n: int) -> int:# 初始化dp数组,dp[i]表示i个节点能构成的不同二叉搜索树的数量dp = [0] * (n + 1)dp[0] = 1  # 空树也是一种二叉搜索树# 动态规划计算每个dp[i]的值for i in range(1, n + 1):for j in range(1, i + 1):dp[i] += dp[j - 1] * dp[i - j]return dp[n]  # 返回n个节点能构成的不同二叉搜索树的数量

Python代码解释

  1. 初始化:定义一个 dp 数组,dp[i] 表示 i 个节点能构成的不同二叉搜索树的数量。初始值 dp[0] = 1,表示空树。
  2. 动态规划递推:使用状态转移公式更新 dp 数组,每次根据左子树和右子树的组合方式来累加。
  3. 返回结果:返回 dp[n],即 n 个节点可以构成的不同二叉搜索树的数量。

C++代码

class Solution {
public:int numTrees(int n) {// 初始化dp数组,dp[i]表示i个节点能构成的不同二叉搜索树的数量vector<int> dp(n + 1, 0);dp[0] = 1;  // 空树也是一种二叉搜索树// 动态规划计算每个dp[i]的值for (int i = 1; i <= n; ++i) {for (int j = 1; j <= i; ++j) {dp[i] += dp[j - 1] * dp[i - j];}}return dp[n];  // 返回n个节点能构成的不同二叉搜索树的数量}
};

C++代码解释

  1. 初始化:定义一个 dp 数组,dp[i] 表示 i 个节点能构成的不同二叉搜索树的数量。初始值 dp[0] = 1,表示空树。
  2. 动态规划递推:使用状态转移公式更新 dp 数组,每次根据左子树和右子树的组合方式来累加。
  3. 返回结果:返回 dp[n],即 n 个节点可以构成的不同二叉搜索树的数量。

总结

  • 核心思路:通过递归构建不同的左子树和右子树,利用动态规划求解不同二叉搜索树的数量。每一个根节点的左子树和右子树的组合数相乘即为该根节点对应的不同二叉搜索树的数量。
  • 时间复杂度:时间复杂度为 O(n^2),适合处理中等规模的输入。
  • 动态规划应用:该问题展示了动态规划在树形结构问题中的应用,通过递推和组合的方式有效解决了求解二叉搜索树数量的问题。
http://www.lryc.cn/news/463346.html

相关文章:

  • Nginx UI 一个可以管理Nginx的图形化界面工具
  • Vue向上滚动加载数据时防止内容闪动
  • 基于QT、ARM的智能停车管理系统+高分项目+源码
  • 1.6,unity动画Animator屏蔽某个部位,动画组合
  • 发动机冷却系统排空气
  • 三周精通FastAPI:1 第一步入门
  • RestTemplate基本使用之HTTP实现GET请求和POST请求
  • 2024-10-18 问AI: [AI面试题] 神经网络有哪些不同类型?
  • 【开源免费】基于SpringBoot+Vue.JS课程作业管理系统(JAVA毕业设计)
  • jmeter中对于有中文内容的csv文件怎么保存
  • Leetcode 921 Shortest Path in Binary Matrix
  • 第二十二篇——菲欧几何:相对论的数学基础是什么?
  • 【AI整合包及教程】EchoMimic:开创数字人新时代,让静态图像“活”起来!
  • ArcGIS 最新底图服务地址
  • 【服务器部署】Docker部署小程序
  • 三菱FX PLC设计一个电子钟程序实例
  • 妇女、商业与法律(WBL)(1971-2023年)
  • python 卸载、安装、virtualenv
  • ubuntu24.0离线安装Ollama和纯cpu版本以及对接Spring AI
  • 机器学习核心:监督学习与无监督学习
  • 服务器托管的优缺点有哪些?
  • RestClient查询文档排序、分页和高亮
  • API项目5:申请签名 在线调用接口
  • Google FabricDiffusion:开启3D虚拟试穿新篇章
  • 【开发语言】c++的发展前景
  • 【机器学习】图像识别——计算机视觉在工业自动化中的应用
  • lstm基础知识
  • Linux :at crontab简述
  • Python,Swift,Haskell三种语言在使用正则表达式上的方法对比
  • leetcode力扣刷题系列——【三角形的最大高度】