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

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

  • 题目描述
  • 前言
  • 基本思路
    • 1. 问题定义
      • 二叉搜索树的性质:
    • 2. 理解问题和递推关系
      • 递归构造思想:
      • 状态定义:
      • 递推公式:
      • 终止条件:
    • 3. 解决方法
      • 递归 + 动态规划方法:
      • 伪代码:
      • 特别注意:
    • 4. 进一步优化
    • 5. 小总结
  • Python代码
      • Python代码解释
  • C++代码
      • C++代码解释
  • 总结

题目描述

在这里插入图片描述

前言

不同的二叉搜索树 II 是一个要求构造出所有可能的 二叉搜索树(BST) 的问题。给定一个整数 n,我们需要构造出由 1n 为节点的所有不同形态的二叉搜索树,并返回这些树的根节点列表。该问题与 不同的二叉搜索树 I 不同的是,不仅要求计算不同二叉搜索树的数量,还需要输出所有可能的二叉搜索树的具体结构。


基本思路

1. 问题定义

给定一个整数 n,构造所有包含 1n 的不同二叉搜索树,并返回这些树的根节点列表。每个二叉搜索树的节点只能使用一次,且必须保持 二叉搜索树 的性质。

二叉搜索树的性质:

  • 左子树的所有节点值都小于根节点值。
  • 右子树的所有节点值都大于根节点值。

2. 理解问题和递推关系

递归构造思想:

我们可以使用递归的方法来构造二叉搜索树。对于任意一个 i,它可以作为根节点,1i-1 组成它的左子树,i+1n 组成它的右子树。递归构造左子树和右子树,并将不同的子树组合起来。

状态定义:

  1. 对于区间 [start, end],构造由该区间组成的所有二叉搜索树。
  2. 递归地将每个数字作为根节点,左子树由 [start, i-1] 构造,右子树由 [i+1, end] 构造。
  3. 组合所有左子树和右子树,形成不同的二叉搜索树。

递推公式:

  1. 对于每个根节点 i,构造左子树 generateTrees(start, i-1) 和右子树 generateTrees(i+1, end)
  2. 将左右子树的所有组合与根节点 i 连接,形成不同的树形结构。

终止条件:

  • start > end 时,返回 None,表示当前区间不能构成任何子树。

3. 解决方法

递归 + 动态规划方法:

  1. 定义递归函数 generateTrees(start, end) 来构造 [start, end] 范围内的所有二叉搜索树。
  2. 对于每一个 i 作为根节点,递归构造左子树和右子树,并将其组合。
  3. 最终返回所有构造的树。

伪代码:

function generateTrees(start, end):if start > end:return [None]all_trees = []for i from start to end:# 构造左子树和右子树left_trees = generateTrees(start, i-1)right_trees = generateTrees(i+1, end)# 组合左右子树与根节点for each left in left_trees:for each right in right_trees:root = new TreeNode(i)root.left = leftroot.right = rightall_trees.append(root)return all_trees

特别注意:

  • 递归调用会确保每个节点 i 都尝试作为根节点,并且分别生成左右子树。最终所有树形结构都被记录在结果列表中。

4. 进一步优化

  • 缓存递归结果:可以用备忘录的方式存储已经计算过的子树组合,避免重复计算,进一步优化效率。

5. 小总结

  • 问题思路:利用递归和分治的思想构造出所有二叉搜索树的结构,确保每个节点都作为一次根节点,并递归构造左右子树。
  • 时间复杂度:时间复杂度较高,因每次递归会构造不同的树形结构,复杂度为 超指数级别

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


Python代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def generateTrees(self, n: int) -> list[TreeNode]:if n == 0:return []# 递归函数,生成从start到end的所有二叉搜索树def generateTrees(start, end):if start > end:return [None]  # 返回一个空树all_trees = []  # 存储所有可能的二叉搜索树for i in range(start, end + 1):# 构造左子树和右子树left_trees = generateTrees(start, i - 1)right_trees = generateTrees(i + 1, end)# 组合所有的左子树和右子树for left in left_trees:for right in right_trees:root = TreeNode(i)  # 以i作为根节点root.left = leftroot.right = rightall_trees.append(root)return all_treesreturn generateTrees(1, n)

Python代码解释

  1. 定义递归函数generateTrees(start, end) 用于生成从 startend 所有不同的二叉搜索树。
  2. 递归构造:对于每个 i 作为根节点,递归构造左右子树的所有可能组合。
  3. 返回结果:最终返回所有可能的树形结构的根节点列表。

C++代码

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<TreeNode*> generateTrees(int n) {if (n == 0) return {};// 递归函数,生成从start到end的所有二叉搜索树return generateTrees(1, n);}vector<TreeNode*> generateTrees(int start, int end) {if (start > end) return {nullptr};  // 返回一个空树vector<TreeNode*> all_trees;  // 存储所有可能的二叉搜索树for (int i = start; i <= end; ++i) {// 构造左子树和右子树vector<TreeNode*> left_trees = generateTrees(start, i - 1);vector<TreeNode*> right_trees = generateTrees(i + 1, end);// 组合所有的左子树和右子树for (TreeNode* left : left_trees) {for (TreeNode* right : right_trees) {TreeNode* root = new TreeNode(i);  // 以i作为根节点root->left = left;root->right = right;all_trees.push_back(root);}}}return all_trees;}
};

C++代码解释

  1. 定义递归函数generateTrees(start, end) 用于生成从 startend 所有不同的二叉搜索树。
  2. 递归构造:对于每个 i 作为根节点,递归构造左右子树的所有可能组合。
  3. 返回结果:最终返回所有可能的树形结构的根节点列表。

总结

  • 核心思想:通过递归和分治的思想,将问题分解为左右子树的组合问题。每个节点都可以作为根节点,递归构造其左子树和右子树,再组合这些树形结构。
  • 复杂度分析:由于需要构造所有可能的树,时间复杂度较高,是 超指数级别 的问题。这类问题适合使用动态规划或递归解决,但无法避免高复杂度。
  • 递归的应用:本问题是递归和分治思想的典型应用,尤其适合解决树形结构的构造问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/54922.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

sentinel dashboard改造落地设计实现解释(一)-分布式fetcher和metrics存储/搜索

背景 微服务是目前java主流架构,微服务架构技术栈有,服务注册中心,网关,熔断限流,服务同学,配置中心等组件,其中,熔断限流主要3个功能特性,限流,熔断,快速失败。Sentinel是阿里开源的熔断限流组件,sentinel dashboard是演示级别,表现在metrics采集是单机版,metri…

Linux内核 -- 文件系统之超级块 super_operations 字段作用与用法

struct super_operations 字段的作用与用法 super_operations 是 Linux 内核中定义的一个结构体&#xff0c;用于描述与文件系统超级块 (super_block) 相关的操作。这些操作涵盖了文件系统的创建、删除、挂载、卸载等。 结构体定义 struct super_operations {struct inode *…

如何使用vscode的launch.json来debug调试

1、创建一个launch.json文件 选择Python Debugger&#xff0c;再选择Python文件&#xff0c;创建处理如下 默认有下面五个参数 "name": "Python Debugger: Current File","type": "debugpy","request": "launch"…

C++ struct 和 class 的区别、C++结构体和C结构体的区别等基础知识。

特性C structC classC struct默认访问控制符publicprivate全部公开支持成员函数是是否继承支持是是否模板支持是是否运算符重载是是否 在C中&#xff0c;struct 和 class 是两种非常相似的用户定义类型&#xff0c;二者有一些关键区别。C的 struct 与 C 语言中的 struct 也存在…

金九银十软件测试面试题(800道)

今年你的目标是拿下大厂offer&#xff1f;还是多少万年薪&#xff1f;其实这些都离不开日积月累的过程。 为此我特意整理出一份&#xff08;超详细笔记/面试题&#xff09;它几乎涵盖了所有的测试开发技术栈&#xff0c;非常珍贵&#xff0c;人手一份 肝完进大厂 妥妥的&#…

【LeetCode】动态规划—123. 买卖股票的最佳时机 III(附完整Python/C++代码)

动态规划—123. 买卖股票的最佳时机 III 题目描述前言基本思路1. 问题定义2. 理解问题和递推关系状态定义&#xff1a;状态转移公式&#xff1a;初始条件&#xff1a; 3. 解决方法动态规划方法伪代码&#xff1a; 4. 进一步优化5. 小总结 Python代码Python代码解释 C代码C代码解…

07_23 种设计模式之《桥接模式》

文章目录 一、桥接模式基础知识二、桥接模式实战应用 一、桥接模式基础知识 桥接模式定义&#xff1a;将抽象部分与它的实现部分分离&#xff0c;使它们都可以 独立地变化。桥接模式的结构图如下&#xff1a; Abstraction&#xff1a;抽象部分的接口。 RefinedAbstraction&…

Python基础之List列表用法

1、创建列表 names ["张三","李四","王五","Mary"] 2、列表分片 names[1]&#xff1a;获取数组的第2个元素。 names[1:3]&#xff1a;获取数组的第2、第3个元素。包含左侧&#xff0c;不包含右侧。 names[:3]等同于names[0:3]&…

List子接口

1.特点&#xff1a;有序&#xff0c;有下标&#xff0c;元素可以重复 2.方法&#xff1a;包含Collection中的所有方法&#xff0c;还包括自己的独有的方法&#xff08;API中查找&#xff09; 还有ListIterator&#xff08;迭代器&#xff09;&#xff0c;功能更强大。 包含更多…

llava1.5论文阅读

Improved Baselines with Visual Instruction Tuning 通过视觉指令微调增强的基线方法 论文摘要&#xff1a; 我们发现&#xff0c;LLaVA中的全连接视觉语言连接器非常强大且数据效率高。 3.3 数据和模型的scaling 受到将线性投影转变为多层感知机&#xff08;MLP&#xff0…

支付宝支付Java+uniapp支付宝小程序

JS&#xff1a; request.post(/vip/pay, {//这是自己写的java支付接口id: this.vipInfo.id,payWay: alipay-mini}).then((res) > {let success (res2) > {//前端的支付成功回调函数this.$refs.popup.close();// 支付成功刷新当前页面setTimeout(() > {this.doGetVipI…

机器学习/数据分析--用通俗语言讲解时间序列自回归(AR)模型,并用其预测天气,拟合度98%+

时间序列在回归预测的领域的重要性&#xff0c;不言而喻&#xff0c;在数学建模中使用及其频繁&#xff0c;但是你真的了解ARIMA、AR、MA么&#xff1f;ACF图你会看么&#xff1f;&#xff1f; 时间序列数据如何构造&#xff1f;&#xff1f;&#xff1f;&#xff0c;我打过不少…

读书笔记 - 虚拟化技术 - 0 QEMU/KVM概述与历史

《QEMU/KVM源码解析与应用》 - 王强 概述 虚拟化简介 虚拟化思想 David Wheeler&#xff1a;计算机科学中任何问题都可以通过增加一个中间层来解决。 虚拟化思想存在与计算机科学的各个领域。 主要思想&#xff1a;通过分层将底层的复杂&#xff0c;难用的资源虚拟抽象为简…

32单片机 低功耗模式

以下是一个基于STM32的低功耗模式示例代码&#xff0c;展示如何将STM32微控制器置于低功耗模式&#xff0c;并在特定条件下唤醒它。这个示例使用的是STM32 HAL库。 ### 示例代码&#xff1a;进入睡眠模式并使用外部中断唤醒 c #include "stm32f4xx_hal.h" // 函数声明…

笔记本电脑按住电源键强行关机,对电脑有伤害吗?

电脑卡住了&#xff0c;我们习惯性地按住电源键或者直接拔掉电源强制关机&#xff0c;但这种做法真的安全吗&#xff1f;会不会对电脑造成伤害呢&#xff1f; 其实&#xff0c;按住电源键关机和直接拔掉电源关机是不一样的。它们在硬件层面有着本质区别。 按住电源键关机 当…

网络常用配置和运维命令以及使用方法

一、网络运维常见配置及命令 以下是一些整理简单网络常用配置和运维命令 1、ifconfig/ipconfig&#xff1a;查看和配置网络接口配置。 用法&#xff1a;ifconfig 或 ipconfig2、route/netstat -r&#xff1a;查看路由表。 用法&#xff1a;route -n 或 netstat -r3、netsta…

Spring Cloud 3.x 集成eureka快速入门Demo

1.什么是eureka&#xff1f; Eureka 由 Netflix 开发&#xff0c;是一种基于REST&#xff08;Representational State Transfer&#xff09;的服务&#xff0c;用于定位服务&#xff08;服务注册与发现&#xff09;&#xff0c;以实现中间层服务的负载均衡和故障转移&#xff…

工业和自动化领域常见的通信协议

在工业和自动化领域&#xff0c;有多种常见的通信协议&#xff0c;主要用于设备间的通信、数据传输和控制。 Modbus&#xff1a; 类型&#xff1a;串行通信协议用途&#xff1a;广泛用于工业自动化设备间的通信&#xff0c;如PLC、传感器和执行器。优点&#xff1a;简单、开放且…

day01-Qt5入门

day01-Qt5入门 窗体应用 1.1 窗体基类说明 创建项目在details中编辑器提供了三个基类&#xff0c;分别是 QMainWindows、Qwidget、QDialog 1、 QMainWindow QMainWindow 类提供一个有菜单条、锚接窗口&#xff08;例如工具条&#xff09;和一个状态条的主应用 程序窗口。…

【系统架构设计师】案例专题六(8大系统架构设计之1): 信息系统架构设计考点梳理

更多内容请见: 备考系统架构设计师-核心总结目录 文章目录 一、信息系统架构基本概念二、信息系统架构1、信息系统架构分类2、信息系统常用4种架构模型3、企业信息系统的总体框架三、信息系统架构设计方法1、ADM架构开发方法2、信息化总体架构方法3、TOGAF的目标、思想和组件四…