LC 106.从中序与后序遍历序列构造二叉树

106. 从中序与后序遍历序列构造二叉树

给定两个整数数组 inorderpostorder ,其中 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]

提示:

  • 1 ≤ i n o r d e r . l e n g t h ≤ 3000 1 \leq inorder.length \leq 3000 1inorder.length3000
  • postorder.length == inorder.length
  • − 3000 ≤ i n o r d e r [ i ] , p o s t o r d e r [ i ] ≤ 3000 -3000 \leq inorder[i], postorder[i] \leq 3000 3000inorder[i],postorder[i]3000
  • inorderpostorder 都由 不同 的值组成
  • postorder 中每一个值都在 inorder
  • inorder 保证是树的中序遍历
  • postorder 保证是树的后序遍历

解法一(递归+分治+Map哈希)

思路分析:

  1. 对于该题,首先思考;中序遍历为:左中右,后序遍历为:左右中,因此通过后序遍历可以确认二叉树的根节点,然后通过根节点可以对中序遍历进行切割成:左中序右中序;然后根据得到的左中序长度,可以对后序遍历进行切割成:左后序右后序
  2. 以此类推,通过递归分治的方式,可以从根节点建立一个二叉树。
  3. 同时思考递归的参数和返回值,因为题目要求构造一个二叉树,所以 返回值类型为TreeNode,然后对于递归的参数则包括,中序遍历数组、后序遍历数组、中序数组起始位置、中序数组末尾位置、后序数组起始位置、后序数组末尾位置。
  4. 对于递归的边界条件,则当后序遍历数组为null时,返回null,当由后序遍历索引起始及末尾位置得;数组长度为1时,直接返回
  5. 对于递归的过程,则是构造中间节点,以及递归构造左右节点
  6. 同时对于如何根据后序数组,对中序数组进行分割,可以使用Map哈希表的方式,避免对中序数组进行反复查询。

实现代码如下:

class Solution {public TreeNode buildTree(int[] inorder, int[] postorder) {if (postorder == null)return null;	// 边界条件// 构造哈希表Map<Integer, Integer> inMap = new HashMap<>();for (int i = 0; i < inorder.length; i++) {inMap.put(inorder[i], i);}return doBuildTree(inorder, postorder, inMap, 0, inorder.length-1, 0, postorder.length-1);}private TreeNode doBuildTree(int[] inorder, int[] postorder, Map<Integer, Integer> inMap, int inS, int inE, int postS, int postE) {if (inE < 0 || postE < 0 || inS > inE || postS > postE || inS >= inorder.length || postS >= postorder.length) // 考虑边界问题return null;// 根据后序遍历数组 末尾索引 获取该子树根节点值int rootValue = postorder[postE];TreeNode node = new TreeNode(rootValue);	// 构造二叉树if (postS == postE)		// 若此时后序数组 起始索引和末尾索引相等 说明为叶子节点return node;	// 直接返回// 根据根节点值 对中序数组进行分割 获取分割位置索引int index = inMap.get(rootValue);// 递归获取左右子树node.left = doBuildTree(inorder, postorder, inMap, inS, index-1, postS, postS+index-1-inS);node.right = doBuildTree(inorder, postorder, inMap, index+1, inE, postS+index-inS, postE-1);return node;}
}

提交结果如下:

解答成功:
执行耗时:2 ms,击败了62.35% 的Java用户
内存消耗:43.5 MB,击败了13.55% 的Java用户

复杂度分析:

  • 时间复杂度: O ( n + m ) O(n+m) O(n+m),需要遍历数组
  • 空间复杂度: O ( n + m ) O(n+m) O(n+m),考虑递归对空间的消耗

优化解法一

思路分析:

  1. 通过对解法一代码的执行流程,发现递归函数doBuildTree中的inorder参数可以省略
  2. 且对于doBuildTree函数中的边界问题判断,由于初始inEPostE均为len-1inSpostS初始为0,因此对于inE < 0的判断与inS >= inorder.length的判断包含在inS > inE中,可省略

实现代码如下:

class Solution {public TreeNode buildTree(int[] inorder, int[] postorder) {if (postorder == null)return null;	// 边界条件// 构造哈希表Map<Integer, Integer> inMap = new HashMap<>();for (int i = 0; i < inorder.length; i++) {inMap.put(inorder[i], i);}return doBuildTree(postorder, inMap, 0, inorder.length-1, 0, postorder.length-1);}private TreeNode doBuildTree(int[] postorder, Map<Integer, Integer> inMap, int inS, int inE, int postS, int postE) {if (inS > inE || postS > postE) // 考虑边界问题return null;// 根据后序遍历数组 末尾索引 获取该子树根节点值int rootValue = postorder[postE];TreeNode node = new TreeNode(rootValue);	// 构造二叉树if (postS == postE)		// 若此时后序数组 起始索引和末尾索引相等 说明为叶子节点return node;	// 直接返回// 根据根节点值 对中序数组进行分割 获取分割位置索引int index = inMap.get(rootValue);// 递归获取左右子树node.left = doBuildTree(postorder, inMap, inS, index-1, postS, postS+index-1-inS);node.right = doBuildTree(postorder, inMap, index+1, inE, postS+index-inS, postE-1);return node;}
}

提交结果如下:

解答成功:
执行耗时:2 ms,击败了62.35% 的Java用户
内存消耗:43.6 MB,击败了10.93% 的Java用户

复杂度分析:

  • 时间复杂度: O ( n + m ) O(n+m) O(n+m),遍历中序数组和后序数组
  • 空间复杂度: O ( n + m ) O(n+m) O(n+m),考虑每层递归传递参数对空间消耗。

解法二(递归+分治+Map)

思路分析:

  1. 跟据官方题解,将中序数组、后序数组,以及提交查询的Map变量,均改为全局遍历,即不需要作为递归函数参数,可在递归函数内访问。
  2. 因为后序遍历中,最后一个元素为子树的根节点,所以先递归获取右子树,再递归获取左子树

实现代码如下:

class Solution {int[] inorder;		// 中序遍历数组int[] postorder;	// 后序遍历数组Map<Integer, Integer> inMap;	// 中序遍历数组 索引表int postIndex;public TreeNode buildTree(int[] inorder, int[] postorder) {if (postorder == null)return null;	// 边界条件this.inorder = inorder;this.postorder = postorder;postIndex = postorder.length-1;// 构造哈希表inMap = new HashMap<>();for (int i = 0; i < inorder.length; i++) {inMap.put(inorder[i], i);}return doBuildTree(0, inorder.length-1);}private TreeNode doBuildTree(int inLeft, int inRight) {if (inLeft > inRight)	// 说明此时为空树return null;int value = postorder[postIndex];	// 根据postIndex 来确定当前子树 中节点值TreeNode node = new TreeNode(value);// 根据 中间节点值 获取分割中序数组索引int index = inMap.get(value);postIndex--;	// 移动所指向的根节点// 先获取右子树node.right = doBuildTree(index+1, inRight);// 再获取左子树node.left = doBuildTree(inLeft, index-1);return node;}
}

提交结果如下:

解答成功:
执行耗时:1 ms,击败了99.58% 的Java用户
内存消耗:43.2 MB,击败了32.11% 的Java用户

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n)n表示树的节点个数
  • 空间复杂度: O ( n ) O(n) O(n),需要使用 O ( n ) O(n) O(n)的空间存储哈希表,同时 O ( h ) O(h) O(h)的空间进行递归(即二叉树的高度),且h < n

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

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

相关文章

个人主页导航源码

源码简介 个人主页导航源码&#xff0c;个人主页导航源码&#xff0c;一款带后台的个人导航主页源码。 搭建环境 PHP 5.2 Nginx Mysql5.6 安装教程 1.上传源码压缩包到网站目录并解压 2.访问网站域名安装提示进行安装即可 后台路径为&#xff1a;https://域名/admin/ …

ngrok 内网穿透使用

title: ngrok 内网穿透使用 search: 2024-02-29 文章目录 背景Windows安装ngrok指令授权ngrok个人用户Authtoken穿透 http 或 https 服务ngrok的代理http指令ngrok获得静态域名指令ngrok的代理ssh指令 背景 这次寒假回家&#xff0c;很无奈&#xff0c;很多东西放在项目组服务…

Vue2(十一):脚手架配置代理、github案例、插槽

一、脚手架配置代理 1.回顾常用的ajax发送方式&#xff1a; &#xff08;1&#xff09;xhr 比较麻烦&#xff0c;不常用 &#xff08;2&#xff09;jQuery 核心是封装dom操作&#xff0c;所以也不常用 &#xff08;3&#xff09;axios 优势&#xff1a;体积小、是promis…

微软Azure推出9种逼真AI语音服务;OpenAI有限开放Voice Engine访问权限

&#x1f680; 微软Azure推出9种逼真AI语音服务 摘要&#xff1a;微软Azure团队在2023年9月对外宣布&#xff0c;针对商业客户推出了一系列逼真的AI语音服务。最近&#xff0c;该公司进一步表示&#xff0c;这些服务现已包含9种更为真实的人工智能声音&#xff0c;并且已于所有…

PostgreSQL:所有支持的数据类型及建表语句实例

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 一、引言 在当今这个数据驱动的时代&#xff0c;数据库已经成为了企业和个人不可或缺的工具。而在众多数据库产品中&#xff0c;PostgreSQL以其强大的功能和高度的可扩展性&#xff0c;受到了越来越多开发者的青睐。…

ZC706+AD9361 运行 open WiFi

先到github上下载img&#xff0c;网页链接如下&#xff1a; https://github.com/open-sdr/openwifi?tabreadme-ov-file 用win32 Disk lmager 把文件写入到SD卡中&#xff0c;这一步操作会把SD卡重新清空&#xff0c;注意保存数据。这个软件我会放在最后的网盘链接中 打开linu…

对接中泰极速行情 | DolphinDB XTP 插件使用教程

XTP 是中泰证券推出的高性能交易平台&#xff0c;专为专业投资者提供高速行情及交易系统&#xff0c;旨在提供优质便捷的市场接入通道。目前支持股票、基金、ETF、债券、期权等多个市场&#xff0c;可满足不同投资者需求。 基于 XTP 官方 C SDK&#xff0c;DolphinDB 开发了 X…

使用hping3网络工具构造TCP/IP数据包和进行DDos攻击

1 概述 hping3是一个强大的命令行工具&#xff0c;用于生成、发送和解析TCP/IP协议的数据包。它是开源的网络安全工具&#xff0c;由Salvatore Sanfilippo开发&#xff0c;主要应用于网络审计、安全测试和故障排查等领域。hping3不仅可以作为普通的网络连通性检测工具&#xf…

【蓝桥杯第十三届省赛B】(部分详解)

九进制转十进制 #include <iostream> #include<math.h> using namespace std; int main() {cout << 2*pow(9,3)0*pow(9,2)2*pow(9,1)2*pow(9,0) << endl;return 0; }顺子日期 #include <iostream> using namespace std; int main() {// 请在此…

ROS2从入门到精通1-2:详解ROS2服务通信机制与自定义服务

目录 0 专栏介绍1 服务通信模型2 服务模型实现(C)3 服务模型实现(Python)4 自定义服务5 话题、服务通信的异同 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握ROS2底层基本分布式原理&#xff0c;并具有机器人建模和应用ROS2进行实际项目的开发和调试的工程能力。…

智慧公厕是什么?智慧公厕的主要功能、特点?

智慧公厕&#xff0c;顾名思义&#xff0c;是指应用了智能科技的公共厕所&#xff0c;旨在提供更加便捷、舒适、智能化的卫生服务。相比传统的公厕&#xff0c;智慧公厕不仅拥有更加智能化的设备&#xff0c;还配备了远程监控与管理系统&#xff0c;以及节能环保技术&#xff0…

如何选择优质的外贸网站建设公司?

在当今数字化时代&#xff0c;外贸行业越来越重视在线渠道的发展&#xff0c;而外贸网站建设作为企业对外联系的重要窗口&#xff0c;扮演着至关重要的角色。选择一家优质的外贸网站建设公司&#xff0c;不仅能帮助企业提升品牌形象&#xff0c;还能有效扩大海外市场。那么&…

微信小程序【从入门到精通】——服务器的数据交互

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

linux C:变量、运算符

linux C 文章目录 变量运算符 一、变量 [存储类型] 数据类型 标识符 值 标识符&#xff1a;由数字、字母、下划线组成的序列&#xff0c;不能以数字开头。 数据类型&#xff1a;基本数据类型构造类型 存储类型&#xff1a;auto static…

Linux(CentOS7)配置系统服务以及开机自启动

目录 前言 两种方式 /etc/systemd/system/ 进入 /etc/systemd/system/ 文件夹 创建 nginx.service 文件 重新加载 systemd 配置文件 ​编辑 配置开机自启 /etc/init.d/ 进入 /etc/init.d/ 文件夹 创建 mysql 文件 编写脚本内容 添加/删除系统服务 配置开机自启 …

【MySQL笔记】SELECT COUNT(*) 的时候,加不加where条件有差别吗?

文章目录 前言实验结论 前言 这部分很多帖子都只在问题里罗列下&#xff0c;好像也没详细解答 其实就是跟InnoDB优先走二级索引的优化有关&#xff0c;前面也提到了”优化的前提是查询语句中不包含where条件和group by条件“ 还不太了解这个优化的朋友可以看上一篇帖子 实验 …

编曲知识13:弦乐技法应用 合成器应用 声场摆位

弦乐技法 技法分类 Sustain(长音)类: Legato、Port、Gliss、Tremolo、Trills Staccato(短音)类: Staccato、Pizzicato、Spiccato Legato:连奏 Port:滑音 Gliss:慢速滑音 Tremolo:震音 Trills:颤音 Staccato:顿弓 Pizzicato:拨奏 Spiccato:跳弓 长音类技法 主…

从0到1:兼职招聘小程序开发笔记(一)

可行性分析 兼职招聘小程序&#xff1a;为雇主和求职者提供便利的平台&#xff0c;旨在帮助雇主招聘兼职员工&#xff0c;并让求职者寻找合适的兼职工作。提供简单、快捷的方式来匹配兼职岗位和候选人&#xff0c;节省了招聘和求职的时间和精力。其主要功能模块包括&#xff1…

C练习题(1)

变种水仙花&#xff08;来自牛课网&#xff09; 题目 变种水仙花数 - Lily Number&#xff1a;把任意的数字&#xff0c;从中间拆分成两个数字&#xff0c;比如1461 可以拆分成&#xff08;1和461&#xff09;,&#xff08;14和61&#xff09;,&#xff08;146和1),如果所有拆…

力扣刷题Days29-128.最长连续数列(js)

目录 1&#xff0c;题目 2&#xff0c;代码 2.1自己实现 2.2哈希表 3&#xff0c;学习与收获 枚举思想&#xff1a; 遍历的核心逻辑 碎碎念 本题 先是想到利用数组排序&#xff0c;从而简化遍历处理逻辑&#xff0c;再在提交错误提醒的情况下&#xff0c;考虑到数组中存…