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

算法日记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 递归地构建:

  1. 创建一个根节点,其值为 nums 中的最大值。
  2. 递归地在最大值 左边 的 子数组前缀上 构建左子树。
  3. 递归地在最大值 右边 的 子数组后缀上 构建右子树。

返回 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;
}
  1. 空节点处理

    • 首先判断 root1 是否为空。如果 root1 为空,直接返回 root2。这是因为如果有一棵树为空,直接返回另一棵树即可,不需要再合并操作。
  2. 递归合并

    • 如果 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;
}
  1. 空节点处理

    • 首先检查当前节点 root 是否为空。如果为空,意味着在当前分支上已经搜索到叶子节点仍未找到目标值,因此返回 null 表示未找到。
  2. 目标值匹配

    • 如果当前节点的值 root.val 等于目标值 val,则直接返回当前节点 root,表示找到了目标节点。
  3. 递归搜索

    • 如果目标值 val 小于当前节点的值 root.val,则递归调用 searchBST(root.left, val),在左子树中继续搜索目标值。
    • 如果目标值 val 大于当前节点的值 root.val,则递归调用 searchBST(root.right, val),在右子树中继续搜索目标值。
  4. 返回结果

    • 无论是从左子树还是右子树返回的结果,将其赋给 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(中序后序遍历序列构造二叉树|最大、合并、搜索二叉树)

一、中序后序序列构造二叉树 题目&#xff1a; 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,…...

【科研】# Taylor Francis 论文 LaTeX template模版 及 Word模版

【科研写论文】系列 文章目录 【科研写论文】系列前言一、Word 模板&#xff08;附下载网址&#xff09;&#xff1a;二、LaTeX 版本方法1&#xff1a;直接网页端打开&#xff08;附网址&#xff09;方法2&#xff1a;直接下载到本地电脑上编辑下载地址说明及注意事项 前言 给…...

Linux网络配置及常见命令!

vim /etc/sysconfig/network-scripsts/ifcfg-ens33&#xff08;图形界面配置网络&#xff09; Xshell rz:上传&#xff08;从Windows到Linux&#xff09; sz&#xff1a;下载&#xff1a;&#xff08;从Linux到Windows&#xff09;&#xff08;后接文件手工输入&#xff09;…...

linux之shell脚本实战

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…...

文件上传漏洞(ctfshow web151-161)

Web151 F12修改源代码 exts后面png改为php 这样就可以上传php的文件了 Web152&#xff1a; 考点&#xff1a;后端不能单一校验 就是要传图片格式&#xff0c;抓个包传个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部署对话语言大模型-网页访问

目录 &#x1f345;点击这里查看所有博文 随着人工智能技术的飞速发展&#xff0c;AI已经不再是遥不可及的高科技概念&#xff0c;而是逐渐融入到我们的日常生活中。从智能手机的语音助手到家庭中的智能音箱&#xff0c;再到工业自动化和医疗诊断&#xff0c;AI的应用无处不在…...

CentOS搭建Apache服务器

安装对应的软件包 [roothds ~]# yum install httpd mod_ssl -y 查看防火墙的状态和selinux [roothds ~]# systemctl status firewalld [roothds ~]# cat /etc/selinux/config 若未关闭&#xff0c;则关闭防火墙和selinux [roothds ~]# systemctl stop firewalld [roothds ~]# …...

CDGA|数据治理:安全如何贯穿数据供给、流通、使用全过程

随着信息技术的飞速发展&#xff0c;数据已经成为企业运营、社会管理和经济发展的核心要素。然而&#xff0c;数据在带来巨大价值的同时&#xff0c;也伴随着诸多安全风险。因此&#xff0c;数据治理的重要性日益凸显&#xff0c;它不仅仅是对数据的简单管理&#xff0c;更是确…...

32单片机bootloader程序

一&#xff0c;单片机为什么要使用bootloader 1、使用bootloader的好处 1) 程序隔离&#xff1a;可以同时存在多个程序&#xff0c;只要flash空间够大&#xff0c;或者通过外挂flash&#xff0c;可以实现多个程序共存&#xff0c;在多个程序之间切换使用。 2&#xff09;方便程…...

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的并行任务处理&#xff0c;每个GPU运行独立的任务&#xff0c;以加速整体的处理速度。 实现机制: 进程隔离: 利用multiprocessing.Process为每个GPU创建独立的工作进程。 GPU资源限制: 通过设置CUDA_VISIBLE_DEVICES环境变量&…...

项目部署到服务器

(相关资源都给出来了) 1 下载MobaXterm,然后打开 正常连接输入你的服务器IP&#xff0c;用户名可以起名为root 2 将JDK,Tomcat,mysql安装包 布置到服务器中&#xff08;JDK官网地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#java8 mysql官网地址: …...

Idea2024 创建Meaven项目没有src文件夹

1、直接创建 新建maven项目&#xff0c;发现没有src/main/java 直接新建文件夹&#xff1a;右击项目名->new->Directory 可以看到idea给出了快捷创建文件夹的选项&#xff0c;可以根据需要创建&#xff0c;这里点击src/main/java 回车&#xff0c;可以看到文件夹已经创建…...

LeetCode 2766.重新放置石块:哈希表

【LetMeFly】2766.重新放置石块&#xff1a;哈希表 力扣题目链接&#xff1a;https://leetcode.cn/problems/relocate-marbles/ 给你一个下标从 0 开始的整数数组 nums &#xff0c;表示一些石块的初始位置。再给你两个长度 相等 下标从 0 开始的整数数组 moveFrom 和 moveTo…...

基于STM32的农业大棚温湿度采集控制系统的设计

目录 1、设计要求 2、系统功能 3、演示视频和实物 4、系统设计框图 5、软件设计流程图 6、原理图 7、主程序 8、总结 &#x1f91e;大家好&#xff0c;这里是5132单片机毕设设计项目分享&#xff0c;今天给大家分享的是智能教室。 设备的详细功能见网盘中的文章《8、基…...

go语言的命名规则

身为前端为什么去学go语言呢&#xff1f;我认为go在未来可能会给我带来一些收益。自认为收益是去做一件事情不可缺少的因素&#xff0c;就好像是你努力之后得到回报&#xff0c;努力的欲望会越来越强。《Head First Go》这本书里作者有一句话&#xff0c;如果你已经掌握了一门编…...

新增ClamAV病毒扫描功能、支持Java和Go运行环境,1Panel开源面板v1.10.12版本发布

2024年7月19日&#xff0c;现代化、开源的Linux服务器运维管理面板1Panel正式发布了v1.10.12版本。 在这一版本中&#xff0c;1Panel新增了多项实用功能。社区版方面&#xff0c;1Panel新增ClamAV病毒扫描功能、支持Java和Go运行环境&#xff0c;同时1Panel还新增了文件编辑器…...

Windows通过命令查看mac : getmac

要查看本机网卡mac&#xff0c;可以通过ipconfig /all 显示&#xff0c;但输出内容过多 可以通过getmac命令查看 示例 C:\Users\Desktop> getmac物理地址 传输名称暂缺 没有硬件 1C-1B-B5-04-E2-7D \Device\Tcpip_{80096E40-D51D-490C-9AF7-…...

Android笔试面试题AI答之Android系统与综合类(1)

答案仅供参考&#xff0c;来着文心一言、Kimi.ai 目录 1.简述嵌入式实时操作系统&#xff0c;Android 操作系统属于实时操作系统吗?嵌入式实时操作系统简述Android操作系统是否属于实时操作系统 2.简述Android系统的优势和不足&#xff1f;3.简述Android的系统架构 &#xff1…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...