数据结构与算法——Java实现 54.力扣1008题——前序遍历构造二叉搜索树

不要谩骂以前的自己

他当时一个人站在雾里也很迷茫

                        ​​​​​​​        ​​​​​​​        ​​​​​​​—— 24.11.6

1008. 前序遍历构造二叉搜索树

给定一个整数数组,它表示BST(即 二叉搜索树 )的 序遍历 ,构造树并返回其根。

保证 对于给定的测试用例,总是有可能找到具有给定需求的二叉搜索树。

二叉搜索树 是一棵二叉树,其中每个节点, Node.left 的任何后代的值 严格小于 Node.val , Node.right 的任何后代的值 严格大于 Node.val

二叉树的 前序遍历 首先显示节点的值,然后遍历Node.left,最后遍历Node.right

示例 1:

输入:preorder = [8,5,1,7,10,12]
输出:[8,5,10,1,7,null,12]

示例 2:

输入: preorder = [1,3]
输出: [1,null,3]

提示:

  • 1 <= preorder.length <= 100
  • 1 <= preorder[i] <= 10^8
  • preorder 中的值 互不相同

方法1 遍历递归插入法

题目中输入的(先)前序遍历序列表示:根 - 左 - 右 进行遍历,输入后应输出构建好的二叉搜索树节点的层序遍历序列,按照前序遍历的结果遍历二叉搜索树的每一个节点进行判断然后更新逐个插入

返回值返回的是二叉搜索树层序遍历的结果

先序遍历数组构建了一个二叉搜索树。bstFromPreorder 方法负责初始化根节点并遍历数组,insert 方法负责将每个元素插入合适的位置

时间复杂度:O(n) = n * logn

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public TreeNode bstFromPreorder(int[] preorder){// preorder 前序遍历结果TreeNode root = new TreeNode(preorder[0]);for (int i = 1; i < preorder.length; i++) {int val = preorder[i];insert(root,val);}return root;}private TreeNode insert(TreeNode node, int val) {if (node == null){return new TreeNode(val);}if (val < node.val){node.left = insert(node.left,val);} else if (val > node.val) {node.right = insert(node.right,val);}return node;}
}


方法2 上下限法

1.遍历前序遍历结果数组中每一个值,根据值创建节点,由二叉搜索树的特性,以当前节点作为左右子树的上下限,进行插入判断,分别对各个孩子及上层节点进行判断,然后将各个子树创建完成,最后合并成一个整树

每个节点若成功创建都有:左孩子上限,右孩子上限

2.处理下一个值时,如果超过此上限,则上个值得孩子为 null值,那么

        ① 将 null 作为上个节点的孩子

        ② 不能创建节点对象

        ③ 直到不超过上限为止

3.重复 1.2. 两步


解题过程

  • 初始化:定义一个全局索引变量i,用于跟踪当前处理的前序数组中的位置。
  • 主函数:调用insert方法,初始最大值设为Integer.MAX_VALUE。
  • 递归插入:
  • 检查当前索引是否超出数组长度,如果是则返回null。
  • 获取当前索引处的值val。
  • 如果val大于当前允许的最大值max,则返回null(因为这违反了二叉搜索树的性质)。
  • 创建新节点,并递归地构建其左子树(左子树的所有节点值都必须小于当前节点值),然后构建右子树(右子树的所有节点值都必须小于max但可以大于当前节点值)。
  • 返回根节点:最终返回构建好的二叉搜索树的根节点。

时间复杂度:O(n)

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {int i = 0;public TreeNode bstFromPreorder(int[] preorder) {return insert(preorder,Integer.MAX_VALUE);}private TreeNode insert(int[] preorder ,int max){if(i == preorder.length){return null;}int val = preorder[i];if(val > max){return null;}TreeNode node = new TreeNode(val);i++;node.left = insert(preorder,val);node.right = insert(preorder,max);return node;}
}


方法3 分治法递归

根据前序遍历中的结果确定根节点,小于根节点的为左子树,大于根节点的为右子树,将左子树和右子树分别递归代入以上判断步骤中,直至判断完所有元素

分而治之思想

前序遍历的第 1 个结点一定是二叉树的根结点;

由于构造出来的是 BST,第 1 个结点后面被分成了两个子区间:

第 1 个子区间里所有的元素都严格小于根结点 -> 递归构建成根结点的左子树;

第 2 个子区间里所有的元素都严格大于根结点 -> 递归构建成根结点的右子树。


/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public TreeNode bstFromPreorder(int[] preorder) {int len = preorder.length;if (len == 0) {return null;}return partition(preorder, 0, len - 1);}//    使用 preorder 的子区间 [left, right] 构建二叉树private TreeNode partition(int[] preorder, int left, int right) {if (left > right) {return null;}TreeNode root = new TreeNode(preorder[left]);if (left == right) {return root;}int i = left;while (i + 1 <= right && preorder[i + 1] < preorder[left]) {i++;}// 此时子区间 [left + 1..i] 所有元素都 < preorder[left]//  [i + 1..right] 所有元素都 > preorder[left]root.left = partition(preorder, left + 1, i);root.right = partition(preorder, i + 1, right);return root;}
}

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

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

相关文章

【Leecode】Leecode刷题之路第46天之全排列

题目出处 46-全排列-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 46-全排列-官方解法 预备知识 回溯法&#xff1a;一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解…

势不可挡 创新引领 | 生信科技SOLIDWORKS 2025新品发布会·苏州站精彩回顾

2024年11月01日&#xff0c;由生信科技举办的SOLIDWORKS 2025新产品发布会在江苏苏州圆满落幕。现场邀请到制造业的专家学者们一同感受SOLIDWORKS 2025最新功能&#xff0c;探索制造业数字化转型之路。 在苏州站活动开场&#xff0c;达索系统专业客户事业部华东区渠道经理马腾飞…

CatLIP,加速2.7倍!采用分类损失的CLIP水准的预训练视觉编码器

CatLIP&#xff0c;加速2.7倍&#xff01;采用分类损失的CLIP水准的预训练视觉编码器 FesianXu 20241018 at Wechat Search Team 前言 传统的CLIP采用对比学习的方式进行预训练&#xff0c;通常需要汇聚多张节点的多张设备的特征向量以进行打分矩阵的计算&#xff0c;训练速度…

linux笔记(selinux)

一、概述 定义SELinux&#xff08;Security - Enhanced Linux&#xff09;是一种基于 Linux 内核的强制访问控制&#xff08;MAC&#xff09;安全机制。它为 Linux 系统提供了更细粒度的安全策略&#xff0c;增强了系统的安全性。目的主要目的是限制进程对系统资源&#xff08;…

江西省补贴性线上职业技能培训管理平台(刷课系统)

江西省补贴性线上职业技能培训管理平台(刷课系统) 目的是为了刷这个网课 此系统有两个版本一个是脚本运行&#xff0c;另外一个是可视化界面运行 可视化运行 技术栈:flask、vue3 原理: 通过分析网站接口&#xff0c;对某些接口加密的参数进行逆向破解&#xff0c;从而修改请求…

Scala 中 set 的实战应用 :图书管理系统

1. 创建书籍集合 首先&#xff0c;我们创建一个可变的书籍集合&#xff0c;用于存储图书馆中的书籍信息。在Scala中&#xff0c;mutable.Set可以用来创建一个可变的集合。 val books mutable.Set("朝花惜拾", "活着") 2. 添加书籍 我们可以使用操作符…

简单介绍一下mvvm mvc mvp以及区别、历史

MVC&#xff08;Model - View - Controller&#xff09; 因MVC架构的灵活性&#xff0c;架构图形式很多&#xff0c;仅供参考 历史&#xff1a; MVC 是最早出现的软件架构模式之一&#xff0c;其历史可以追溯到 20 世纪 70 年代&#xff0c;最初被用于 Smalltalk - 80 环境。…

“高级Java编程复习指南:深入理解并发编程、JVM优化与分布式系统架构“

我的个人主页 接下来我将方享四道由易到难的编程题&#xff0c;进入我们的JavaSE复习之旅。 1&#xff1a;大小写转换------题目链接 解题思路&#xff1a; 在ASCII码表中&#xff0c;⼤写字⺟A-Z的Ascii码值为65- 90&#xff0c;⼩写字⺟a-z的Ascii码值为97-122。每个字 ⺟…

设备租借系统(源码+文档+部署+讲解)

本文将深入解析“设备租借系统”的项目&#xff0c;探究其架构、功能以及技术栈&#xff0c;并分享获取完整源码的途径。 系统概述 本项目名称为设备租借系统&#xff0c;是对企业内部设备进行信息化管理的系统&#xff0c;可以实现设备的借用、归还、状态跟踪等功能&#xff…

使用 PageHelper 在 Spring Boot 项目中实现分页查询

目录 前言1. 项目环境配置1.1 添加 PageHelper 依赖1.2 数据库和 MyBatis 配置 2. 统一的分页响应类3. 使用 PageHelper 实现分页查询3.1 Service 层分页查询实现3.2 PageHelper 分页注意事项 4. 控制层调用示例5. 常见问题与解决方案5.1 java.util.ArrayList cannot be cast t…

【C++】C++移动语义、左值右值、左值引用右值引用、移动构造函数、std::move、移动赋值操作符

二十五、C移动语义、左值和右值、左值引用右值引用、移动构造函数、std::move、移动赋值操作符 本部分讨论一些更高级的C特性&#xff1a;C移动语义。但是讲移动语义之前我们得先了解什么左值右值、左值引用和右值引用。 1、C的左值和右值、左值引用和右值引用左值是有地址的…

【国内中间件厂商排名及四大中间件对比分析】

国内中间件厂商排名 随着新兴技术的涌入&#xff0c;一批国产中间件厂商破土而出&#xff0c;并在短时间内迅速发展&#xff0c;我国中间件市场迎来洗牌&#xff0c;根据市占率&#xff0c;当前我国中间件厂商排名依次为&#xff1a;东方通、宝兰德、中创股份、金蝶天燕、普元…

Android自启动管控

1. 自启动管控需求来源 自启动、关联启动、交叉启动、推送启动等现象的泛滥除了对个人信息保护带来隐患外&#xff0c;还会导致占用过多的系统CPU和内存资源&#xff0c;造成系统卡顿、发热、电池消耗过快&#xff1b;还可能引入一些包含“恶意代码”的进程在后台隐蔽启动&…

C++上机实验|多态性编程练习

1.实验目的 (1)理解多态性的概念。 (2)掌握如何用虚函数实现动态联编 (3)掌握如何利用虚基类。 2.实验内容 设计一个飞机类 plane,由它派生出歼击机类fighter和轰炸机类 bomber,歼击机类fighter 和轰炸机类bomber 又共同派生出歼轰机(多用途战斗机)。利用虚函数和虚基类描述…

ctfshow(328)--XSS漏洞--存储型XSS

Web328 简单阅读一下页面。 是一个登录系统&#xff0c;存在一个用户管理数据库。 那么我们注册一个账号&#xff0c;在账号或者密码中植入HTML恶意代码&#xff0c;当管理员访问用户管理数据库页面时&#xff0c;就会触发我们的恶意代码。 思路 我们向数据库中写入盗取管理员…

Kubernetes的概述与架构

Kubernetes 的概述 Kubernetes 是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;方便进行声明式配置和自动化。Kubernetes 拥有一个庞大且快速增长的生态系统&#xff0c;其服务、支持和工具的使用范围广泛。 Kubernetes 这个名字源于…

crond 任务调度 (Linux相关指令:crontab)

相关视频链接 crontab 进行 定时任务 的设置 概述 任务调度&#xff1a;是指系统在某个时间执行的特定的命令或程序 任务调度的分类&#xff1a; 1.系统工作&#xff1a;有些重要的工作必须周而复始地执行。如病毒扫描等。 2.个别用户可能希望执行某些程序&#xff0c;比如…

408最后冲刺阶段,怎么做题才能考到120+?

C哥专业提供——计软考研院校选择分析专业课备考指南规划 重要性排序如下&#xff1a;真题占据首位&#xff0c;紧随其后的是王道模拟题&#xff0c;王道书与题目则紧随其后&#xff0c;而408统考配套习题&#xff08;高教版&#xff09;与之大致相当。 真题&#xff0c;无疑…

uniapp上拉刷新下拉加载

方法一&#xff1a; z-paging 的组件库&#xff1a; show-loading-more-no-more-view"false" 该属性控制是否显示 "加载更多" 或 "没有更多" 的提示。如果设为 false&#xff0c;则不会显示这些提示。如果设为 true&#xff0c;当数据加载完毕…

Java I/O(输入/输出)——针对实习面试

目录 Java I/O&#xff08;输入/输出&#xff09;什么是Java I/O流&#xff1f;字节流和字符流有什么区别&#xff1f;什么是缓冲流&#xff1f;为什么要使用缓冲流&#xff1f;Java I/O中的设计模式有哪些&#xff1f;什么是BIO&#xff1f;什么是NIO&#xff1f;什么是AIO&am…