算法日记day 20(中序后序遍历序列构造二叉树|最大、合并、搜索二叉树)
一、中序后序序列构造二叉树
题目:
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
示例 1:

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出:[3,9,20,null,null,15,7]
示例 2:
输入:inorder = [-1], postorder = [-1] 输出:[-1]
思路:
中序遍历顺序:左、中、右 后序遍历顺序:左、右、中
首先在后序中确定最后一个节点为二叉树的根节点,再以此根节点在中序遍历中寻找左子树和右子树,和后序遍历中的左子树和右子树,依次循环递归其左右子树,直到遍历完所有节点为止
代码:
public class Solution {public TreeNode buildTree(int[] inorder, int[] postorder) {// 检查特殊情况,如果输入的中序或后序序列长度为0,则返回空树if (postorder.length == 0 || inorder.length == 0) {return null;}// 调用递归辅助方法来构建二叉树,并返回根节点return buildHelper(inorder, 0, inorder.length, postorder, 0, postorder.length);}private TreeNode buildHelper(int[] inorder, int inorderStart, int inorderEnd,int[] postorder, int postorderStart, int postorderEnd) {// 如果后序序列的起始索引等于结束索引,说明当前子树为空,返回nullif (postorderStart == postorderEnd) {return null;}// 后序遍历序列的最后一个元素是当前子树的根节点值int rootVal = postorder[postorderEnd - 1];TreeNode root = new TreeNode(rootVal); // 创建根节点int middleIndex;// 在中序遍历序列中找到根节点的位置for (middleIndex = inorderStart; middleIndex < inorderEnd; middleIndex++) {if (inorder[middleIndex] == rootVal) {break;}}// 计算左子树和右子树在中序遍历序列中的边界int leftInorderStart = inorderStart;int leftInorderEnd = middleIndex;int rightInorderStart = middleIndex + 1;int rightInorderEnd = inorderEnd;// 计算左子树和右子树在后序遍历序列中的边界int leftPostorderStart = postorderStart;int leftPostorderEnd = postorderStart + (middleIndex - inorderStart);int rightPostorderStart = leftPostorderEnd;int rightPostorderEnd = postorderEnd - 1;// 递归构建左子树和右子树,并连接到当前根节点root.left = buildHelper(inorder, leftInorderStart, leftInorderEnd,postorder, leftPostorderStart, leftPostorderEnd);root.right = buildHelper(inorder, rightInorderStart, rightInorderEnd,postorder, rightPostorderStart, rightPostorderEnd);return root; // 返回当前根节点}
}
buildTree方法接收两个参数:inorder表示中序遍历序列,postorder表示后序遍历序列。- 首先检查特殊情况:如果
postorder或inorder的长度为 0,则返回null,表示空树。 - 调用
buildHelper方法来实际构建二叉树,并返回根节点。 buildHelper方法是一个递归方法,用来构建二叉树的具体逻辑。- 首先检查递归终止条件:如果
postorderStart == postorderEnd,说明当前子序列为空,返回null。 - 从
postorder中获取当前子树的根节点值rootVal,并创建根节点root。 - 在
inorder中查找根节点值rootVal的位置middleIndex,用于分割左右子树的中序遍历序列。 - 计算左子树和右子树的中序遍历序列的起始和结束索引。
- 根据中序遍历序列的划分,计算左右子树在后序遍历序列中的起始和结束索引。
- 递归构建左子树和右子树,将其分别连接到当前根节点
root的左右孩子上。
二、最大二叉树
题目:
给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:
- 创建一个根节点,其值为
nums中的最大值。 - 递归地在最大值 左边 的 子数组前缀上 构建左子树。
- 递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums 构建的 最大二叉树 。
示例 1:

输入:nums = [3,2,1,6,0,5] 输出:[6,3,5,null,2,0,null,null,1] 解释:递归调用如下所示: - [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。- [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。- 空数组,无子节点。- [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。- 空数组,无子节点。- 只有一个元素,所以子节点是一个值为 1 的节点。- [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。- 只有一个元素,所以子节点是一个值为 0 的节点。- 空数组,无子节点。
示例 2:

输入:nums = [3,2,1] 输出:[3,null,2,null,1]
思路:
首先遍历数组中的最大值为根节点,后以该根节点为分割点区分开左右子树,然后分别对左右子树中的元素再进行如上操作,找到每次分割的左右子树中的最大元素作为下一层的父节点
代码:
public TreeNode constructMax(int[] nums, int leftIndex, int rightIndex) {if (rightIndex - leftIndex < 1)return null;if (rightIndex - leftIndex == 1)return new TreeNode(nums[leftIndex]);int maxIndex = leftIndex; int maxValue = nums[maxIndex];// 寻找最大值及其索引for (int i = leftIndex + 1; i < rightIndex; i++) {if (nums[i] > maxValue) {maxValue = nums[i];maxIndex = i;}}// 用最大值构建根节点TreeNode root = new TreeNode(maxValue);// 递归构建左子树和右子树root.left = constructMax(nums, leftIndex, maxIndex);root.right = constructMax(nums, maxIndex + 1, rightIndex);return root;
}
constructMax方法接受四个参数:nums数组、左边界leftIndex和右边界rightIndex。- 首先,检查当前子数组的长度,如果小于等于
1,则返回相应的树结点(空结点或叶子结点)。 - 否则,通过遍历找到当前子数组中的最大值及其索引
maxIndex。 - 创建根节点
root,值为maxValue。 - 递归地构建左子树和右子树:
- 左子树递归调用
constructMax(nums, leftIndex, maxIndex),处理左半部分的数组。 - 右子树递归调用
constructMax(nums, maxIndex + 1, rightIndex),处理右半部分的数组。
- 左子树递归调用
public TreeNode constructMaximumBinaryTree(int[] nums) {return constructMax(nums, 0, nums.length);
}
返回constructMax方法构建的子树的根节点root,最终完成整棵最大二叉树的构建。
三、合并二叉树
题目:
给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
示例 1:

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7] 输出:[3,4,5,5,4,null,7]
示例 2:
输入:root1 = [1], root2 = [1,2] 输出:[2,2]
思路:
同时操作两个二叉树对应的节点进行相加操作,可以分情况讨论,两树间存在空节点、两树间都有节点的情况
第一类代码:
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {// 如果两棵树的当前节点都为空,则返回空节点if (root1 == null && root2 == null) {return null;}// 创建新的树节点,值先设为0TreeNode root = new TreeNode(0);// 如果root1为空但root2不为空,以root2的值作为当前节点的值,递归处理左右子树if (root1 == null && root2 != null) {root.val = root2.val;root.left = mergeTrees(null, root2.left);root.right = mergeTrees(null, root2.right);} // 如果root1不为空但root2为空,以root1的值作为当前节点的值,递归处理左右子树else if (root1 != null && root2 == null) {root.val = root1.val;root.left = mergeTrees(root1.left, null);root.right = mergeTrees(root1.right, null);} // 如果root1和root2都不为空,以它们的值相加作为当前节点的值,递归处理左右子树else {root.val = root1.val + root2.val;root.left = mergeTrees(root1.left, root2.left);root.right = mergeTrees(root1.right, root2.right);}// 返回合并后的根节点return root;
}
使用递归的简洁方法
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {// 如果root1为空,则返回root2if (root1 == null)return root2;// 如果root2为空,则返回root1if (root2 == null)return root1;// 如果root1和root2都不为空,将它们的值相加root1.val += root2.val;// 递归处理左子树,将合并后的左子树设为root1的左子树root1.left = mergeTrees(root1.left, root2.left);// 递归处理右子树,将合并后的右子树设为root1的右子树root1.right = mergeTrees(root1.right, root2.right);// 返回合并后的根节点root1return root1;
}
-
空节点处理:
- 首先判断
root1是否为空。如果root1为空,直接返回root2。这是因为如果有一棵树为空,直接返回另一棵树即可,不需要再合并操作。
- 首先判断
-
递归合并:
- 如果
root1不为空且root2也不为空,则将root1和root2的值相加,更新root1的值。 - 然后分别递归合并它们的左子树和右子树:
root1.left = mergeTrees(root1.left, root2.left);root1.right = mergeTrees(root1.right, root2.right);
- 这样就递归地将
root1和root2的左子树和右子树合并,并将合并后的子树作为root1的左右子树。
- 如果
四、二叉搜索树中的搜索
二叉搜索树:左子树的值比根节点小,右子树的值比根节点大,且其每个子树也都是二叉搜索树
题目:
给定二叉搜索树(BST)的根节点 root 和一个整数值 val。
你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。
示例 1:

输入:root = [4,2,7,1,3], val = 2 输出:[2,1,3]
示例 2:

输入:root = [4,2,7,1,3], val = 5 输出:[]
代码:
递归
//递归法
public TreeNode searchBST(TreeNode root, int val) {// 如果当前节点为空,表示已经搜索到叶子节点仍未找到目标值,返回 nullif (root == null)return null;// 如果当前节点的值等于目标值,直接返回当前节点if (root.val == val)return root;// 声明一个用于存放搜索结果的变量,默认为 nullTreeNode result = null;// 如果目标值小于当前节点的值,向左子树递归搜索if (val < root.val) {result = searchBST(root.left, val);}// 如果目标值大于当前节点的值,向右子树递归搜索if (val > root.val) {result = searchBST(root.right, val);}// 返回最终的搜索结果,可能为找到的节点或者 nullreturn result;
}
-
空节点处理:
- 首先检查当前节点
root是否为空。如果为空,意味着在当前分支上已经搜索到叶子节点仍未找到目标值,因此返回null表示未找到。
- 首先检查当前节点
-
目标值匹配:
- 如果当前节点的值
root.val等于目标值val,则直接返回当前节点root,表示找到了目标节点。
- 如果当前节点的值
-
递归搜索:
- 如果目标值
val小于当前节点的值root.val,则递归调用searchBST(root.left, val),在左子树中继续搜索目标值。 - 如果目标值
val大于当前节点的值root.val,则递归调用searchBST(root.right, val),在右子树中继续搜索目标值。
- 如果目标值
-
返回结果:
- 无论是从左子树还是右子树返回的结果,将其赋给
result变量。 - 最终返回
result,可能是找到的目标节点或者null(如果未找到)。
- 无论是从左子树还是右子树返回的结果,将其赋给
迭代
//迭代法
public TreeNode searchBST(TreeNode root, int val) {// 使用循环来在二叉搜索树中搜索目标值while (root != null) {if (val < root.val) {root = root.left; // 如果目标值小于当前节点的值,向左子树移动} else if (val > root.val) {root = root.right; // 如果目标值大于当前节点的值,向右子树移动} else {return root; // 找到目标节点,返回当前节点}}return null; // 如果循环结束仍未找到目标节点,返回 null
}
- 使用
while循环在二叉搜索树中搜索目标值。循环条件是root != null,即当前节点不为空时继续搜索。 - 如果目标值
val小于当前节点的值root.val,则向左子树移动root = root.left;。 - 如果目标值
val大于当前节点的值root.val,则向右子树移动root = root.right;。 - 如果目标值与当前节点的值相等,则直接返回当前节点
return root;。
今天的学习就到这里了
相关文章:
算法日记day 20(中序后序遍历序列构造二叉树|最大、合并、搜索二叉树)
一、中序后序序列构造二叉树 题目: 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入:inorder [9,3,15,20,…...
【科研】# Taylor Francis 论文 LaTeX template模版 及 Word模版
【科研写论文】系列 文章目录 【科研写论文】系列前言一、Word 模板(附下载网址):二、LaTeX 版本方法1:直接网页端打开(附网址)方法2:直接下载到本地电脑上编辑下载地址说明及注意事项 前言 给…...
Linux网络配置及常见命令!
vim /etc/sysconfig/network-scripsts/ifcfg-ens33(图形界面配置网络) Xshell rz:上传(从Windows到Linux) sz:下载:(从Linux到Windows)(后接文件手工输入)…...
linux之shell脚本实战
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…...
文件上传漏洞(ctfshow web151-161)
Web151 F12修改源代码 exts后面png改为php 这样就可以上传php的文件了 Web152: 考点:后端不能单一校验 就是要传图片格式,抓个包传个png的图片 然后bp抓包修改php后缀解析 然后放包 Web153-web156 在php代码中可以使用“{}”代替“[]” …...
小猪佩奇.js
闲着没事 使用js 画一个小猪佩奇把 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</tit…...
人工智能AI合集:Ollama部署对话语言大模型-网页访问
目录 🍅点击这里查看所有博文 随着人工智能技术的飞速发展,AI已经不再是遥不可及的高科技概念,而是逐渐融入到我们的日常生活中。从智能手机的语音助手到家庭中的智能音箱,再到工业自动化和医疗诊断,AI的应用无处不在…...
CentOS搭建Apache服务器
安装对应的软件包 [roothds ~]# yum install httpd mod_ssl -y 查看防火墙的状态和selinux [roothds ~]# systemctl status firewalld [roothds ~]# cat /etc/selinux/config 若未关闭,则关闭防火墙和selinux [roothds ~]# systemctl stop firewalld [roothds ~]# …...
CDGA|数据治理:安全如何贯穿数据供给、流通、使用全过程
随着信息技术的飞速发展,数据已经成为企业运营、社会管理和经济发展的核心要素。然而,数据在带来巨大价值的同时,也伴随着诸多安全风险。因此,数据治理的重要性日益凸显,它不仅仅是对数据的简单管理,更是确…...
32单片机bootloader程序
一,单片机为什么要使用bootloader 1、使用bootloader的好处 1) 程序隔离:可以同时存在多个程序,只要flash空间够大,或者通过外挂flash,可以实现多个程序共存,在多个程序之间切换使用。 2)方便程…...
MongoDB - 数组更新操作符:$、$[]、$pop、$pull、$push、$each、$sort、$slice、$position
文章目录 1. $1. 更新数组中的值2. 更新数组中的嵌入文档 2. $[]1. 更新数组中的所有元素2. 更新数组中的所有嵌入文档 3. $pop1. 删除数组的第一个元素2. 删除数组的最后一个元素 4. $pull1. 删除所有等于指定值的项2. 删除与指定条件匹配的所有项3. 从文档数组中删除项4. 从嵌…...
多GPU并行处理[任务分配、进程调度、资源管理、负载均衡]
1. 多GPU并行处理设计 设计思路: 实现基于多GPU的并行任务处理,每个GPU运行独立的任务,以加速整体的处理速度。 实现机制: 进程隔离: 利用multiprocessing.Process为每个GPU创建独立的工作进程。 GPU资源限制: 通过设置CUDA_VISIBLE_DEVICES环境变量&…...
项目部署到服务器
(相关资源都给出来了) 1 下载MobaXterm,然后打开 正常连接输入你的服务器IP,用户名可以起名为root 2 将JDK,Tomcat,mysql安装包 布置到服务器中(JDK官网地址:https://www.oracle.com/java/technologies/downloads/#java8 mysql官网地址: …...
Idea2024 创建Meaven项目没有src文件夹
1、直接创建 新建maven项目,发现没有src/main/java 直接新建文件夹:右击项目名->new->Directory 可以看到idea给出了快捷创建文件夹的选项,可以根据需要创建,这里点击src/main/java 回车,可以看到文件夹已经创建…...
LeetCode 2766.重新放置石块:哈希表
【LetMeFly】2766.重新放置石块:哈希表 力扣题目链接:https://leetcode.cn/problems/relocate-marbles/ 给你一个下标从 0 开始的整数数组 nums ,表示一些石块的初始位置。再给你两个长度 相等 下标从 0 开始的整数数组 moveFrom 和 moveTo…...
基于STM32的农业大棚温湿度采集控制系统的设计
目录 1、设计要求 2、系统功能 3、演示视频和实物 4、系统设计框图 5、软件设计流程图 6、原理图 7、主程序 8、总结 🤞大家好,这里是5132单片机毕设设计项目分享,今天给大家分享的是智能教室。 设备的详细功能见网盘中的文章《8、基…...
go语言的命名规则
身为前端为什么去学go语言呢?我认为go在未来可能会给我带来一些收益。自认为收益是去做一件事情不可缺少的因素,就好像是你努力之后得到回报,努力的欲望会越来越强。《Head First Go》这本书里作者有一句话,如果你已经掌握了一门编…...
新增ClamAV病毒扫描功能、支持Java和Go运行环境,1Panel开源面板v1.10.12版本发布
2024年7月19日,现代化、开源的Linux服务器运维管理面板1Panel正式发布了v1.10.12版本。 在这一版本中,1Panel新增了多项实用功能。社区版方面,1Panel新增ClamAV病毒扫描功能、支持Java和Go运行环境,同时1Panel还新增了文件编辑器…...
Windows通过命令查看mac : getmac
要查看本机网卡mac,可以通过ipconfig /all 显示,但输出内容过多 可以通过getmac命令查看 示例 C:\Users\Desktop> getmac物理地址 传输名称暂缺 没有硬件 1C-1B-B5-04-E2-7D \Device\Tcpip_{80096E40-D51D-490C-9AF7-…...
Android笔试面试题AI答之Android系统与综合类(1)
答案仅供参考,来着文心一言、Kimi.ai 目录 1.简述嵌入式实时操作系统,Android 操作系统属于实时操作系统吗?嵌入式实时操作系统简述Android操作系统是否属于实时操作系统 2.简述Android系统的优势和不足?3.简述Android的系统架构 ࿱…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...
热烈祝贺埃文科技正式加入可信数据空间发展联盟
2025年4月29日,在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上,可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞,强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...
