Java LeetCode篇-深入了解二叉树的经典解法(多种方式实现:构造二叉树)

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍
   

文章目录

        1.0 从前序与中序遍历序列来构造二叉树

        1.1 实现从前序与中序遍历序列来构造二叉树思路   

        1.2 代码实现从前序与中序遍历序列来构造二叉树

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

        2.1 实现从中序与后序遍历序列后遭二叉树思路

        2.2 代码实现从中序与后序遍历序列来构造二叉树

        3.0 根据后缀表达式创建二叉树

        3.1 实现后缀表达式创建二叉树思路

        3.2 代码实现后缀表达式创建二叉树

         4.0 相同的树

        4.1 实现判断两颗树是否相同思路

        4.2 代码实现相同树

         5.0 另一颗树的子树

        5.1 实现判断是否为另一颗树的子树

        5.2 代码实现判断是否为另一颗树的子树


        1.0 从前序与中序遍历序列来构造二叉树

题目:

        给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

OJ链接:

105. 从前序与中序遍历序列构造二叉树

        1.1 实现从前序与中序遍历序列来构造二叉树思路   

        具体思路为:前序遍历的流程先是访问根节点,到左子树,再到右子树的顺序;中序遍历的流程先是左子树,到访问根节点,再到右子树。因此,在前序的序列中的第一个元素就是该树的根节点的值,然后再通过中序的序列中遍历找根节点。接着就可以将其中序的序列进行拆分,在中序序列中根节点的值的左边部分的序列为左子树,在中序序列中根节点的值的右边部分序列为右子树。又接着将前序序列进行拆分,从索引为 1 开始,长度为:与中序序列中左子树的序列数量是一致的,将这一部分称为左子树;从索引 (1+长度)开始到该序列的结束,将这一部分称为右子树。接下来就是子问题了,通过递归,找到当前节点的左右子树。

       具体例子:前序序列 pre = {3,9,20,15,7},中序序列 in = {9,3,15,20,7} 。先找到该树的节点值 int rootValue = pre[0], TreeNode root = new TreeNode(rootValue),创建该树的根节点。接着对中序序列遍历来找到根节点的值,i == 1 ,在中序序列中找左右子树:在索引在该区间 [0,1)是节点的左子树,而在索引为 [2,5)区间是节点的右子树。在前序序列中找左右子树:在索引为 [1,2)是该节点的左子树,而在索引为 [2,5)区间是节点的右子树。

        子问题:那么现在得到了左子树的前序序列 pre = { 9 } ,左子树的中序序列 in = { 9 },接下来的流程跟以上的流程是一样的,先找到该子树的根节点值 9 ,然后创建一个值为 9 的根节点。接着,遍历中序序列来找到根节点的值,该根节点的左部分就是左子树,该节点的右部分就是右子树。那么这里的左右子树都为空,因此节点为 9 的根节点没有左右子树了。

        往上回溯:来到根节点值为 3 的节点。现在得到了右子树的前序序列 pre = {20,15,7} ,右子树的中序序列 in = {15,20,7} ,接下来的过程是一摸一样的,先找到该子树的根节点值为 20 ,创建值为 20 的根节点。然后在中序序列中进行遍历找到根节点的左右子树 :左子树序列为 {15},右子树序列为 {7},接着在前序序列中找左右子树:左子树序列为 {15},右子树序列为 {7} 。又得到了左右前中序列,按同样的道理继续下去即可,通过上面的结论,当左子树前序 {15} 与左子树中序 {15} 一样时,那么在当前的节点值为 15 的根节点没有左右子树了。同理,当右子树前序 {7} 与右子树中序 {7} 一样时,那么在当前的节点值为 7 的根节点没有左右子树了。

        最后回溯,根节点值为 20 的左子树的根节点为 15,右子树的根节点为 7 ,链接起来,一直回溯到结束返回的最后的节点就是该树的根节点(值为 1 的根节点)。

        需要注意的是:注意左闭右开。因为是同一颗树,在前序中的左右子树的长度跟中序中的左右子树的长度是一样的。

        1.2 代码实现从前序与中序遍历序列来构造二叉树

    //根据前序与中序来构造二叉树public TreeNode prevAndInOrderConstructTree(int[] prevOrder, int[] inOrder) {if (prevOrder.length == 0) {return null;}int rootValue = prevOrder[0];TreeNode root = new TreeNode(rootValue);for (int i = 0; i < inOrder.length; i++) {if (inOrder[i] == rootValue) {int[] inLeft = Arrays.copyOfRange(inOrder,0,i);int[] inRight = Arrays.copyOfRange(inOrder,i+1,inOrder.length);int[] prevLeft = Arrays.copyOfRange(prevOrder,1,i + 1);int[] prevRight = Arrays.copyOfRange(prevOrder,i+1,inOrder.length);root.left = prevAndInOrderConstructTree(prevLeft,inLeft);root.right = prevAndInOrderConstructTree(prevRight,inRight);}}return root;}

        只要某一个序列无论是前序或者是中序序列的长度为 0 ,都代表创建二叉树过程结束了。

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

题目:

        给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

示例 1:

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

OJ链接:

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

        2.1 实现从中序与后序遍历序列后遭二叉树思路

        具体思路为:中序的序列先访问左子树,再访问根节点,最后到右子树。后序的序列先访问左子树,再访问右子树,最后才到根节点。因此,可以从后序序列中的最后一个元素得到根节点的值,然后利用该值来创建根节点。接着,在中序序列中遍历查找根节点的值,在中序序列中根节点值左边的序列为左子树序列,在中序序列中根节点的右边为右子树的序列。再接着再后序中获取左子树的序列:从索引为 0 开始长度是中序序列得到的左子树的长度;从后序序列中获取右子树序列:除了左子树的序列和根节点值元素,其余就是右子树的序列了。接下来就是子问题了,递归下去,返回当前的根节点。

        具体例子:中序序列 in = {9,3,15,20,7},后序序列 post = {9,15,7,20,3},通过后序得到该树的根节点的值 3,由这个值来创建值为 3 的根节点。接着通过遍历中序序列,找到值为 3 来定位左右子树,左子树的序列为:{9} ,右子树的序列为:{15,20,7} 。再从中序序列中定位左右子树,左子树为:{9},右子树为:{15,7,20} 。现在得到了左右中后序列,中序左子树:{9} ,后序左子树:{9},通过后序得到根节点,再从中序定位该子树的根节点,这里根节点值为 9 的根节点的左右子树均为 null 。接着回溯,返回的该子树的根节点。

        再到右子树中序 {15,20,7} ,右子树后序 {15,7,20},通过后序序列的最后一个值来创建该子树的根节点,在中序中遍历找到该根节点的值,定位该节点的左右子树。中序的左子树序列 {15},右子树序列 {7};后序的左子树序列 {15},后序的右子树序列 {7} 。

        再接着递归,得到左子树中序 {15} ,左子树后序 {15}。通过后序的最后一个元素就是根节点的值来创建该子树的根节点,然后在中序中定位该根节点的左右子树,这里的左右子树都为 null ,返回根节点即可。得到右子树中序 {7},右子树后序 {7},通过后序的最后一个元素为根节点的值来创建该子树的根节点,然后在中序中定位该根节点的左右子树,恰好,这里的左右子树都为 null ,返回根节点即可。

        最后回溯过程,根节点值为 1 的节点的左子树的根节点为 9 的节点,右子树的根节点为 20 的节点。

        2.2 代码实现从中序与后序遍历序列来构造二叉树

    //根据中序与后序来构造二叉树public TreeNode inAndPostConstructTree(int[] inOrder, int[] postOrder) {if (inOrder.length == 0) {return null;}int rootValue = postOrder[postOrder.length-1];TreeNode root = new TreeNode(rootValue);for (int j = 0; j < inOrder.length; j++) {if (rootValue == inOrder[j]) {int[] inLeft = Arrays.copyOfRange(inOrder,0,j);int[] inRight = Arrays.copyOfRange(inOrder,j+1,inOrder.length);int[] postLeft = Arrays.copyOfRange(postOrder,0,j);int[] postRight = Arrays.copyOfRange(postOrder,j,postOrder.length-1);root.left = inAndPostConstructTree(inLeft,postLeft);root.right = inAndPostConstructTree(inRight,postRight);}}return root;}

        需要注意的定位左右子树的序列长度,中序与后序的左右子树都是一一对应的。也因此,当无论任意一个序列结束,都代表着构造二叉树过程结束。

        3.0 根据后缀表达式创建二叉树

        后缀表达式也叫逆波兰表达式,是一种不需要括号的表达式表示方法。在后缀表达式中,运算符总是在操作数的后面,因此可以通过从左到右扫描表达式来创建二叉树。

        3.1 实现后缀表达式创建二叉树思路

        具体思路为:若遇到数字将其压入栈中;若遇到操作符时,将栈中的右左元素弹出栈,操作符节点进行链接弹出来的左右子树,需要注意的是,第一个弹出来的是右操作数,第二个才是左操作数。链接完之后,将其压入栈中即可。循环结束条件为:将后缀表达式遍历完就结束。最后返回栈中的栈顶元素,就是该树的根节点。

        3.2 代码实现后缀表达式创建二叉树

    //根据后缀表达式创建二叉树public TreeNode suffixCreateTree(String[] s) {LinkedList<TreeNode> stack = new LinkedList<>();for (int i = 0; i < s.length; i++) {String ch = s[i];switch (ch) {case "+","-","*","/" -> {TreeNode right = stack.pop();TreeNode left = stack.pop();TreeNode t = new TreeNode(ch);t.right = right;t.left = left;stack.push(t);}default -> {stack.push(new TreeNode(ch));}}}return stack.peek();}

         4.0 相同的树

题目:

        给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:

输入:p = [1,2,3], q = [1,2,3]
输出:true

OJ链接:

100. 相同的树

        4.1 实现判断两颗树是否相同思路

        具体思路为:使用递归实现,第一种情况:若一个子树为 null ,另一个子树不为 null ,返回 false ;第二种情况:若两个子树都为 null ,则返回 true 。第三种情况:若两个子树的根节点的值不相同时,返回 false 。子过程,判断完左子树,还需判断右子树。

        4.2 代码实现相同树

class Solution {public boolean isSameTree(TreeNode p, TreeNode q) {if( p != null && q == null || p ==null && q != null) {return false;}if(p == null && q == null ){return true;}if(p.val != q.val) {return false;}return isSameTree(p.left, q.left) && isSameTree(p.right,q.right);}
}

        5.0 另一颗树的子树

题目:

        给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

示例 1:

输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true

OJ链接:

572. 另一棵树的子树

         5.1 实现判断是否为另一颗树的子树

        具体思路为:最根本的问题就是判断是否为相同的树,判断该树的子树与另一颗子树是否相同,不断递归下去,只要相同就返回 true 。直到最后递归结束都没有匹配,则返回 false 。

        5.2 代码实现判断是否为另一颗树的子树

class Solution {public boolean isSubtree(TreeNode root, TreeNode subRoot) {if(root == null) {return false;}if(isSameTree(root,subRoot)) {return true;}if(isSubtree(root.left,subRoot)) {return true;}if(isSubtree(root.right,subRoot)) {return true;}return false;}public boolean isSameTree(TreeNode p, TreeNode q) {if( p != null && q == null || p ==null && q != null) {return false;}if(p == null && q == null ){return true;}if(p.val != q.val) {return false;}return isSameTree(p.left, q.left) && isSameTree(p.right,q.right);}
}

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

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

相关文章

计算目标检测和语义分割的PR

需求描述 实际工作中&#xff0c;相比于mAP项目更加关心的是特定阈值下的precision和recall结果&#xff1b;由于本次的GT中除了目标框之外还存在多边形标注&#xff0c;为此&#xff0c;计算IoU的方式从框与框之间变成了mask之间&#xff1b; 本文的代码适用于MMDetection下的…

Java Web 学习之路(2) —— 概念、SpringBoot + MyBatis(controller+service+mapper)开发流程与过程梳理

文章目录 前言1. 常见的一些概念1.1 POJO&#xff08;Plain Ordinary Java Object 简单Java对象&#xff09;1.2 DAO和Mapper 2. Java的三层架构2.1 包的层级结构2.2 交互层 controller&#xff08;用户界面、网页&#xff09;jsp文件2.3 业务处理层 service2.4 Mapper层 3. 注…

2024 年甘肃省职业院校技能大赛信息安全管理与评估赛项规程

2024 年甘肃省职业院校技能大赛高职学生组电子与信息大类信息安全管理与评估赛项规程 一、赛项名称 赛项名称&#xff1a;信息安全管理与评估 赛项类别&#xff1a;团体赛 赛项归属&#xff1a;电子与信息大类 二、竞赛目的 极安云科专注技能竞赛&#xff0c;包含网络建设…

微信小程序css实现的联系客服动画样式

一 、效果 二、代码 wxml <view class"customer-service"><button class"btn" open-type"contact"></button><image class"pic" src"https://ts4.cn.mm.bing.net/th?idOIP-C.3SGSiRPuOU9uH5VNVOMPwgHaHa…

序列的Z变换(信号的频域分析)

1. 关于Z变换 2. 等比级数求和 3. 特殊序列的Z变换 4. 因果序列/系统收敛域的特点 5. 例题

免费的AI文案生成器有哪些?AI文案生成器排行榜

在当今数字化的时代&#xff0c;内容创作已成为许多行业不可或缺的一部分。为了满足日益增长的创作需求&#xff0c;越来越多的人开始寻找能够提高效率、同时保持原创性的解决方案。本文将专心分享一些优质的AI文案生成器。 AI文案生成器的需求 内容创作已经不再是传统媒体和市…

高项备考葵花宝典-项目进度管理输入、输出、工具和技术(上,很详细考试必过)

项目进度管理的目标是使项目按时完成。有效的进度管理是项目管理成功的关键之一&#xff0c;进度问题在项目生命周期内引起的冲突最多。 小型项目中&#xff0c;定义活动、排列活动顺序、估算活动持续时间及制定进度模型形成进度计划等过程的联系非常密切&#xff0c;可以视为一…

C语言基础

常量和常量表达式的区别 #define N 4;又是常量&#xff0c;又是常量表达式&#xff0c;其在编译期预处理阶段就会直接替换 const int M 5;只是常量&#xff0c;不是常量表达式 &#xff0c;其是存储在一块内存区域之内的&#xff0c;但是存储的值不能改变 常量表达式&#xff…

【USB、串口、COM口、TTL、RS-232、RS-485区别详解】

USB&#xff0c;串口&#xff0c;COM口&#xff0c;TTL&#xff0c;RS-232&#xff0c;RS-485区别详解 1. USB&#xff0c;串口&#xff0c;COM口&#xff0c;TTL&#xff0c;RS-232&#xff0c;RS-485区别详解2 USB转TTL2 RS-232转TTL3 USB4 UART5 STM32串口异步通讯需要定义的…

iOS——定位与地图

平时在写项目的时候可能会遇到需要使用定位服务的地方&#xff0c;比如说获取位置和导航等。因此这里我会使用OC自带的库以及苹果系统的地图来获取定位以及显示在地图上。 开始前的设置 在获取定位前&#xff0c;需要在项目文件的info中添加两个关键字&#xff0c;用于向用户…

从零开始的C++(二十一)

C11 1.列表初始化&#xff1a; //允许以下代码正确运行int a[]{1,2,3};//效果与int a[]{1,2,3}一致 即允许省略等于号。同时&#xff0c;允许用花括号对所有自定义类型和内置类型进行初始化&#xff0c;而非以前花括号只能对数组进行初始化。利用花括号对自定义类型初始化时…

LeetCode刷题--- 求根节点到叶节点数字之和

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏&#xff1a;http://t.csdnimg.cn/ZxuNL http://t.csdnimg.cn/c9twt 前言&#xff1a;这个专栏主要讲述递归递归、搜索与回溯算法&#xff0c;所以下面题目主要也是这些算法做的 我讲述…

在python中安装库,会有conda安装,也会有pip安装,conda与pip的区别是什么?

文章目录 一、Conda是什么&#xff1f;二、pip是什么&#xff1f;三、pip与conda的区别&#xff1a;总结 一、Conda是什么&#xff1f; Conda是一个开源的包管理系统&#xff0c;它是Anaconda公司为Python和其他编程语言开发的。它主要用于数据科学和机器学习领域&#xff0c;…

【Vue】日常错误总结(持续更新)

日常遇到的小问题汇总, 内容小篇幅少的就全放这里了, 内容多的会在Vue专栏单独分享~ 目录 【Q】 el-form-item值为 null 或 undefined显示““ 【Q】dialog内组件数据刷新总是延迟慢一拍 问题背景描述 解决方案 代码简单模拟 JS 【Q】el-input 不能输入的解决办法 方法…

Orcal数据库Schema理解、表分区理解

目录 1 Schema1.1 Orcal数据库示例1.2 MySQL数据库示例 2 Orcal表分区2.1 创建表分区2.2 查看表分区2.3 查看指定分区数据 此前未了解过Schema的概念&#xff0c;仅知道Orcal数据库比较侧重这个概念&#xff0c;搜遍全网都&#xff0c;都是啰哩吧嗦的搬抄定义&#xff0c;特此在…

LeetCode算法题解(单调栈)|LeetCode503. 下一个更大元素 II、LeetCode42. 接雨水

一、LeetCode503. 下一个更大元素 II 题目链接&#xff1a;503. 下一个更大元素 II 题目描述&#xff1a; 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的…

LIMoE:使用MoE学习多个模态

文章链接&#xff1a;Multimodal Contrastive Learning with LIMoE: the Language-Image Mixture of Experts 发表期刊&#xff08;会议&#xff09;: NeurIPS 2022 目录 1.背景介绍稀疏模型 2.内容摘要Sparse Mixture-of-Experts ModelsContrastive LearningExperiment Analy…

Kubernetes入门笔记 ——(3)理解pod对象

为什么需要pod 最为熟知的一句话&#xff1a;pod是k8s的最小调度单位。刚开始听到这句话时会想&#xff0c;已经有容器了&#xff0c;k8s为什么还要搞个pod出来&#xff1f;容器和pod是什么关系&#xff1f;容器的本质是进程&#xff0c;而k8s本质上类似操作系统。 熟悉Linux的…

SpringBoot系列之启动成功后执行业务的方法归纳

SpringBoot系列之启动成功后执行业务逻辑。在Springboot项目中经常会遇到需要在项目启动成功后&#xff0c;加一些业务逻辑的&#xff0c;比如缓存的预处理&#xff0c;配置参数的加载等等场景&#xff0c;下面给出一些常有的方法 实验环境 JDK 1.8SpringBoot 2.2.1Maven 3.2…

欧拉回路欧拉路【详解】

1.引入 2.概念 3.解决方法 4.例题 5.回顾 1.引入 经典的七桥问题 哥尼斯堡是位于普累格河上的一座城市&#xff0c;它包含两个岛屿及连接它们的七座桥&#xff0c;如下图所示。 可否走过这样的七座桥&#xff0c;而且每桥只走过一次&#xff1f; 你怎样证明&#xff1f;…