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. 注…

如何同步fork项目原仓库的更新

最简单粗暴的方法&#xff1a;把原来fork的仓库删了重新fork&#xff08;嘿嘿不过这显然是不优雅的&#xff09; 那我们该怎么同步更新呢&#xff1f; 如何在 Github 网页端同步更新&#xff1f; 进入你自己的 fork 过来的仓库。点击 “Pull requests” &#xff0c;如何点击…

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

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

Python基础——正则匹配中高阶用法

1.正则使用变量匹配re.escape() re.escape() 是一个用于转义正则表达式中特殊字符的函数。当我们需要使用变量构建正则表达式模式时&#xff0c;为了避免特殊字符对模式的解析产生影响&#xff0c;我们可以使用 re.escape() 函数来自动转义这些特殊字符。 例如&#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. 例题

navigationBar顶部导航栏,兼容适配所有机型(附完整案例)

思路 隐藏原生样式获取胶囊按钮、状态栏相关数据以供后续计算根据不同机型计算出该机型的导航栏高度,进行适配编写为导航栏公共组件使用组件1. 隐藏原生样式 全局设置 "window": {"navigationStyle": "custom" }单个页面设置 {"navigat…

免费的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;所以下面题目主要也是这些算法做的 我讲述…

【ITK库学习】使用itk库进行图像滤波ImageFilter:邻域滤波

目录 1、itkMeanImageFilter 均值滤波器2、itkMedianImageFilter 中值滤波器3、itkBinaryMedianImageFilter 二值中值滤波器4、扩展itkNeighborhood5、扩展itkNeighborhoodIterator6、扩展itkNeighborhoodOperator 领域滤波是一种信号处理方法&#xff0c;用于去除信号中的噪声…

★560. 和为 K 的子数组(自己做出来了)

560. 和为 K 的子数组 前缀和的知识。 如果要求i~j下标之间的元素和&#xff0c;用前缀和的话&#xff0c;应该是b[j] - b[i-1]&#xff0c;i处的值也应该包括。 所以这个题&#xff0c;前缀和数组就要比原数组整体向后平移一个单元格&#xff0c;不然在求0~n的和的时候没法取…

在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 不能输入的解决办法 方法…

Educational Codeforces Round 156 (Rated for Div. 2)补题

Sum of Three 题目大意&#xff1a;将一个正整数n分成3个不同的正整数x,y,z,保证三个数都不能整除3&#xff0c;如果无法实现就输出NO. 思路&#xff1a;这个题实际上特别简单&#xff0c;我们可以发现当n比较大的时候&#xff0c;我们可以从中取1&#xff0c;然后第二个数也…