【LeetCode 105 106 889】重建二叉树(给定树的前中后序遍历方式中的两种来重建二叉树)

机器学习——Anaconda下载安装教程 Anaconda详细下载安装教程 阅读详情

树的常见遍历方式有:前序遍历,中序遍历,后序遍历,层序遍历,关于这些遍历方式的递归和非递归实现:https://blog.youkuaiyun.com/Applying/article/details/84982712
现在,如果给定前中后序遍历方式中的两种,如何重建二叉树呢?

1. 从前序和中序遍历构建二叉树(LeetCode 105)

这个是三种情况中,最常被问到的题目。LeetCode上也有对应的题目:(LeetCode 105)
在这里插入图片描述
思路:对于前序遍历,其顺序为 (根值)(先序遍历左子树)(先序遍历右子树) 对于中序遍历,其顺序为 (中序遍历左子树)(根值)(中序遍历右子树) 由于题目中默认,节点值是不会重复的,所以我们可以通过按顺序遍历中序遍历的结果,找到根植对应的下标,将中序遍历成功分成三个部分。然后,根据中序遍历切出来的第一部分的左子树遍历结果的长度,来切先序遍历中左子树的部分。
实现代码:

    private static TreeNode buildTree(int[] preorder, int[] inorder) {
        // 判断输入是否为空,是否合法
        if (preorder == null || inorder == null || preorder.length != inorder.length) return null;
        return buildTree(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
    }

    // 注意,这里都是用下标表示
    private static TreeNode buildTree(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) {
        if (preEnd < preStart || inEnd < inStart) return null;
        // 从先序遍历的数组中,获取根植
        TreeNode root = new TreeNode(preorder[preStart]);
        // 从中序数组中寻找根植对应的下标
        int i = inStart;
        for (; i <= inEnd; i++) {
            if (inorder[i] == root.val)
                break;
        }
        // 利用中序遍历的特点,将左子树跟右子树分开
        root.left = buildTree(preorder, preStart + 1, preStart + (i - inStart), inorder, inStart, i - 1);
        root.right = buildTree(preorder, preStart + (i - inStart) + 1, preEnd, inorder, i + 1, inEnd);
        return root;
    }

这个解法还可以进一步利用map的数据结构进行优化:

    private static TreeNode buildTree_(int[] preorder, int[] inorder) {
        if (preorder == null || inorder == null || preorder.length != inorder.length) return null;
        // 将中序遍历的结果放置到map结构中,方便通过根植找下标
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) {
            map.put(inorder[i], i);
        }
        return buildTree(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1, map);
    }

    private static TreeNode buildTree(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd, Map<Integer, Integer> map) {
        if (preEnd < preStart || inEnd < inStart) return null;
        TreeNode root = new TreeNode(preorder[preStart]);
        int i = map.get(root.val);
        root.left = buildTree(preorder, preStart + 1, preStart + (i - inStart), inorder, inStart, i - 1, map);
        root.right = buildTree(preorder, preStart + (i - inStart) + 1, preEnd, inorder, i + 1, inEnd, map);
        return root;
    }

这里最重点就是如何将先序遍历preorder切出其左右子树部分,和中序遍历inorder如何切出左右子树部分,我是这么考虑的:
中序遍历比较容易进行切割,我们通过找根植下标 i,因此,中序遍历 inorder 中,左子树的范围[inStart, i - 1],右子树的范围[i + 1, inEnd]。接下来,看先序遍历,根据先序遍历(根值)(先序遍历左子树)(先序遍历右子树),以及我们可以根据已经切分出来的中序遍历中的左子树的范围来推导先序遍历中左子树的范围,因此,先序遍历 preorder 中,左子树的范围[preStart + 1, preStart + (i - inStart)],其中,i - inStart 为中序遍历中左子树的长度范围。右子树的范围:[preStart + (i - inStart) + 1, preEnd]。

2. 从后序和中序遍历构建二叉树(LeetCode 106)

这个问题对应 LeetCode 106,题目如下:
在这里插入图片描述
思路:这种情况跟第一种类似,同样利用中序,对后序进行切分,实现代码:

    private static TreeNode buildTree(int[] inorder, int[] postorder) {
        if (inorder == null || postorder == null || inorder.length != postorder.length) return null;
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < inorder.length; i++) {
            map.put(inorder[i], i);
        }
        return buildTree(0, inorder.length - 1, 0, postorder.length - 1, inorder, postorder, map);
    }

    private static TreeNode buildTree(int inStart, int inEnd, int postStart, int postEnd,
                                      int[] inorder, int[] postorder, Map<Integer, Integer> map) {
        if (inEnd < inStart || postEnd < postStart) return null;
        TreeNode root = new TreeNode(postorder[postEnd]);
        int i = map.get(root.val);
        root.left = buildTree(inStart, i - 1, postStart, postStart + (i - inStart) - 1, inorder, postorder, map);
        root.right = buildTree(i + 1, inEnd, postStart + (i - inStart), postEnd - 1, inorder, postorder, map);
        return root;
    }

中序遍历 (中序遍历左子树)(根值)(中序遍历右子树) ,而后序遍历 (后序遍历左子树)(后序遍历右子树)(根值) ,类比第一种情况,进行切分即可

3. 从前序和后序遍历构建二叉树(LeetCode 889)

该情况对应LeetCode 889,题目如下:
在这里插入图片描述
这种情况,因为没有中序遍历,对左右子树进行切分,因此出现了可能存在多个符合答案的解。
这里是找其中一个解即可。因此,我的思路是:根据先序 (根值)(先序遍历左子树)(先序遍历右子树) ,后序 (后序遍历左子树)(后序遍历右子树)(根值), 我假设左子树存在,则先序中 preorder[preStart] 为左子树的根植,而在后序遍历中,左子树的根植,将在最后被遍历到,也就是,它所在的位置是(后序遍历左子树)部分中的最后一个元素,因此,可以切割左子树的范围,对应右子树的范围也就出来了。

    private static TreeNode constructFromPrePost(int[] pre, int[] post) {
        if (pre == null || post == null || post.length != pre.length) return null;
        return constructTree(0, pre.length - 1, 0, post.length - 1, pre, post);
    }

    private static TreeNode constructTree(int preStart, int preEnd, int postStart, int postEnd,
                                          int[] pre, int[] post) {
        if (preEnd < preStart || postEnd < postStart) return null;
        TreeNode root = new TreeNode(pre[preStart]);
        if (preEnd == preStart) return root;
        int i = postStart;
        // 找到后序遍历中,左子树的根植的位置
        for (; i <= postEnd; i++) {
            if (post[i] == pre[preStart + 1])
                break;
        }
        root.left = constructTree(preStart + 1, preStart + 1 + (i - postStart), postStart, i, pre, post);
        root.right = constructTree(preStart + 1 + (i - postStart) + 1, preEnd, i + 1, postEnd - 1, pre, post);
        return root;
    }

但,可能有人会说,可能会存在没有左子树的情况,例如:

确实,但按照我们上面的算法,[3, 8, 9] 这一部分,将被划分成左子树的部分,而后子树为 null:
在这里插入图片描述
对于这两种情况,其前序,后序遍历是完全相同的,即,对于求存在的其中一个符合条件的解,这种思路是可行的。

其他 LeetCode 题目解析

视觉Transformer实战 | Token-to-Token Vision Transformer(T2T-ViT)详解与实现 Vision Transformer (ViT) 在计算机视觉领域取得了巨大成功,但标准的 ViT 存在一些局限性,如需要大规模预训练数据、对局部结构建模不足等。Token-to-Token ViT (T2T-ViT) 通过引入渐进式分词过程改进了原始 ViT,使其能够在中小型数据集上取得更好的性能。本节将详细介绍 T2T-ViT 的技术原理,并使用 PyTorch 从零开始实现 T2T-ViT。 阅读详情

相关推荐

primetime如何做voltage scaling

存在这样的情况,标准单元库只有ssgnp0p72vm40c和ssgnp0p9vm40c的libs,但是我们希望它工作在ssgnp0p76vm40c,这样的话就需要用ssgnp0p72vm40c和ssgnp0p9vm40c的libs来scaling出ssgnp0p76vm40c的lib。

qq_34326957的博客 1683

LeetCode重建二叉树详解

LeetCode重建二叉树详解题目描述原理分析(1)大致思路(2)细节阐述代码实现(1)主函数(2)递归函数参数区间的决定递归结束的条件总结 题目描述 原理分析 (1)大致思路 下面讲解一下,前序遍历+中序遍历如何确定一个唯一的二叉树。关于二叉树的基本知识,请看二叉树的基本操作及联系。对此就不再过多重复。对于前序遍历顺序:根、左子树、右子树;对于中序的遍历顺序:左子树、根、右子树。所以通过前序遍历,我们获取前序第一个结点就是这个树的根,再在中序遍历中找到该结点的位置。在中序中,根的左边全部的是属于根左子

cdzg_zzk的博客 1156

SAP PP模块 MRP配置实战:5步完成工厂级物料需求计划激活

本文详细介绍了SAP PP模块中物料需求计划(MRP)的工厂级配置实战,通过5个关键步骤从基础环境准备到最终激活。内容涵盖SPRO后台配置、MRP控制者定义、主数据设置及核心参数调整,帮助顾问快速掌握MRP配置清单的完整流程,确保物料需求计划的高效运行。

weixin_30431445的博客 340

《剑指offer刷题笔记》6、重建二叉树 【c++详细题解】

题目 输入一棵二叉树前序遍历和中序遍历的结果,请重建该二叉树。 注意: 二叉树中每个节点的值都互不相同; 输入的前序遍历和中序遍历一定合法; 样例 给定: 前序遍历是:[3, 9, 20, 15, 7] 中序遍历是:[9, 3, 15, 20, 7] 返回:[3, 9, 20, null, null, 15, 7, null, null, null, null] 返回的二叉树如下所示: 3 / \ 9 20 / \ 15 7 思路 (递归)O(n)O(n)O(

林深不见鹿 的博客 2205

保姆级教程:将YOLOv8模型封装成Docker镜像,集成到CVAT实现自动标注

本文提供了一份详细的保姆级教程,指导如何将YOLOv8模型封装成Docker镜像并集成到CVAT平台,实现自动化标注。通过环境配置、模型服务化封装、Docker镜像构建与优化、CVAT平台集成等步骤,帮助开发者高效完成计算机视觉项目的自动标注工作流,显著提升标注效率。

weixin_28692817的博客 412

【数据结构】面试题整理 共36题

链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和一个指向下一个节点的指针。与数组不同,链表中的元素在内存中不必是连续存储的,这使得链表在插入和删除操作时非常高效。单向链表(Singly Linked List):每个节点只包含一个指向下一个节点的指针。双向链表(Doubly Linked List):每个节点包含两个指针,一个指向下一个节点,一个指向前一个节点。循环链表(Circular Linked List):链表的最后一个节点指向第一个节点,形成一个环。

weixin_44329069的博客 7192

LeetCode剑指offer07重建二叉树题解

剑指offer07重建二叉树题解

Te_g的博客 308

YOLOv8融合改进 更换检测头为Detect_DyHead同时添加C2f_DBB模块

yolov8独家训练测试融合网络结构,提供详细步骤详细代码,手把手教你在yolov8官方包中把检测头更换为Detect_DyHead检测头,并且将原始的C2f模块更换成C2f_DBB模块,提高检测精度,亲测在多个数据集上有涨点!!!!!

分享一些自己改进代码的实例 4747

leetcode之重建二叉树

最头疼的就是做树的题目了,虽然说遇到树,想到的就是递归,想到的就是深度优先搜索,但是总感觉没有get到它的精华所在。 输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3 / \ 9...

HarryXu的博客 314

【制作100个unity游戏之22】3DRPG游戏开发01——项目的设置和导入及渲染管线的安装修复

如果你现在存在一些疑惑unity导入素材为什么是粉紫色的?表示他没有适配我们的URP通用渲染管线,要如何适配呢?素材渲染错误丢失要如何解决?如果你有上面3个任意的问题,那这篇文章同样适合你,我将手把手教你如何安装修复渲染管线,看完你就了解了!在Unity中,他们都是渲染管线,它们的主要区别在于性能和功能。LWRP是早期版本的URP,它专门为移动设备和低端PC设计,旨在提供更高的性能。它使用基于顶点的光照和简化的后处理效果,可以在更低的硬件要求下运行。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2425

Go语言面试:面试中经常被问到的50个经典面试题(附参考答案)

Go语言核心知识点摘要 基础语法与数据结构 make和new区别:new分配零值内存返回指针,make初始化引用类型返回实例 Slice底层:包含指针、长度、容量的结构体,多个slice可共享底层数组 nil与空slice:nil指针为nil,空slice指针非nil但JSON编码不同 Map原理:哈希表实现,非线程安全,扩容策略影响性能 for range注意:循环变量是拷贝,map遍历无序 defer执行:LIFO顺序,函数返回前执行 Struct比较:仅当所有字段可比较时才可比较 参数传递:只有值传递

数据知道的博客 4719

leetcode算法学习(18)——重建二叉树

重建二叉树举例题目描述方法一:递归--复制列表的形式思路代码方法二:递归--哈希表思路代码 举例 例如要重建的是如下二叉树。 其前序遍历和中序遍历如下。 preorder = [3,9,8,5,4,10,20,15,7] inorder = [4,5,8,10,9,3,15,20,7] 前序遍历的第一个元素 3 是根节点,第二个元素 9 可能位于左子树或者右子树,需要通过中序遍历判断。 中序遍历的第一个元素是 4 ,不是根节点 3,说明 9 位于左子树,因为根节点不是中序遍历中的第一个节点。同理,前序

qq_41230076的博客 385

【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part2知识获取与图谱构建、服务搭建

前序文章:其中原项目提供了关系数据如下: 其中五列数据表示:人物1,人物2,人物1与人物2关系,人物1所属家族,人物2所属家族。关系说明:以第一列为例,贾演是贾代化的父亲。下面我们就将这个数据放到neo4j中。这些需要去连接,需要安装这个包: 程序中,我使用去读取配置文件, 其中为了保持配置全局唯一性,使用单例的写法。 后面就是创建构建关系文件,构建neo4j图谱数据了,如下: 后期可能会将构建图谱内容使用flask去生成命令行的方式构建,暂时在开发的过程查看构建情况,便于调试。导入关系后,我们再查看

让算法融入生活,改变生活! 4078

【leetcode】二叉树,654最大二叉树,105根据前序与中序遍历构造二叉树,106根据中序与后序遍列构造二叉树,889根据前序和后序遍历构造二叉树

【leetcode】二叉树,654最大二叉树,105根据前序与中序遍历构造二叉树,106根据中序与后序遍列构造二叉树,889根据前序和后序遍历构造二叉树前言654. 最大二叉树105. 根据前序与中序遍历构造二叉树106. 根据中序与后序遍列构造二叉树889. 根据前序和后序遍历构造二叉树 前言 上篇文章 手把手教你刷二叉树(第一篇) 连刷了三道二叉树题目,很多读者直呼内行。其实二叉树相关的算法真的不难,本文再来三道,手把手带你看看树的算法到底怎么做。 先来复习一下,我们说过写树的算法,关键思路如下: 把题

一个写湿的程序猿 992

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

leetcode105根据前序和中序遍历重建树、106根据中序和后序遍历重建树、889根据前序和后序遍历重建树的任意一种

leetcode105根据前序和中序遍历重建树、106根据中序和后序遍历重建树、889根据前序和后序遍历重建树的任意一种105. 从前序与中序遍历序列构造二叉树106. 从中序与后序遍历序列构造二叉树根据一棵树的中序遍历与后序遍历构造二叉树。889. 根据前序和后序遍历构造二叉树返回与给定的前序和后序遍历匹配的任何二叉树。 这种类型的题其实就是一种套路,只要函数建的对,做这种题就不用受累! 步骤一:建函数,主函数调用。 此函数一般包含主函数的两个参数,前序和中序或者中序和后序和前序和后序;还有步骤二的ind

kuanyew的博客 316

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

超容易理解+模版套路解决LeetCode 前序+中序、中序+后序、前序+后序遍历构造树问题

这三道题的解法类似 都是基于归并排序的分治思想 不断划分左右子树进行解答。下列题1和题2解法几乎完全相同 题三根据前序后序遍历的话需要加以注意 后面详细讲解。

SoulruiA的博客 1462

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

剑指Offer 7 | LeetCode 105/106/889/1008 根据遍历顺序重建二叉树系列(Python)

二叉树的遍历 二叉树的遍历方式有很多种,本文主要讨论三种比较常见的方式:前序遍历、中序遍历及后序遍历。 这三种遍历的区别在于: 前序遍历:先访问根节点,再是左子树,最后是右子树; 中序遍历:先访问左子树,再是根节点,最后是右子树; 后序遍历:先访问左子树,再是右子树,最后是根节点。 下面举一个例子来进行介绍(图片来源于网络): 前序遍历为:[1, 2, 4, 8, 5, 3, 6, 9, 10,...

ChungChinKei' blog 356

重建二叉树(前序中序、中序后序、前序后序)

前序中序:105. 从前序与中序遍历序列构造二叉树 class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { return CreateByPreMid(preorder, inorder, 0, 0, preorder.length); } public TreeNode CreateByPreMid(int[] preorder, int[] inorder, int

朱嫑膘的博客 275

LeetCode 105.106.889. 从前序|后序与中序|后序遍历序列构造二叉树 | C++语言版

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

weixin_45992021的博客 1370

LeetCode刷题—根据两种遍历方式重建二叉树

LeetCode中有三道很类似的题,思路也大同小异,故作一总结。 105,从前序与中序遍历序列构造二叉树,medium 106,根据中序和后序遍历构造二叉树,medium 889,根据前序和后序遍历构造二叉树,medium 这三道题都是给出两种遍历方式,由其遍历顺序可发现规律来重建此二叉树。下面详解105题,后两题思路稍作改变,比较好懂了。 105,从前序与中序遍历序列构造二叉树,medium 根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preo

qq_39181839的博客 354

LeetCode重建二叉树系列问题总结

二叉树天然的递归特性,使得我们可以使用递归算法对二叉树进行遍历和重建。之前已经写过LeetCode二叉树的前序、中序、后序遍历(递归实现),那么本文将进行二叉树的重建,经过对比,会发现二者有着许多相似之处。

码上暴富 850

Java(树的前中后序遍历构造二叉树题型整合)前序和中序、中序和后序、前序和后序遍历序列构造二叉树算法整合归纳

二叉树前序和中序、中序和后序、前序和后序遍历序列构造二叉树算法整合归纳

弹弹霹雳的博客 396

leetcode树之二叉树的创建

前言 前面介绍了二叉树的遍历,这次我们来考虑一下二叉树的创建,给定前中后序遍历的结果,这个时候要还原成二叉树应该怎么做呢? 下面来通过几道题来实际感受一下吧! 105、从前序和中序序列构建二叉树 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。 示例1: 输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 输出: [3,9,20,n

溪语流沙的博客 1370

通过遍历结果构造二叉树

通过遍历结果构造二叉树

如风暖阳的博客 1011

【Leetcode 专题一(树专题)】前、中、后、层次遍历、二叉搜索树、二叉树修改构造、二叉树的一些特殊递归

目录一、前序遍历1.0、前序框架模板1.1、经典题目二、中序遍历2.0、中序框架模板三、后续遍历3.0、后序框架模板四、层次遍历4.0、层次框架模板 一、前序遍历 1.0、前序框架模板 144. 二叉树的前序遍历 递归写法 # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val=0, left=None, right=None): # self.val = val

qq_38253797的博客 555

由任意二叉树的前序遍历序列和中序遍历序列求二叉树的思想方法_算法与数据结构基础 - 二叉树(Binary Tree)...

二叉树基础满足这样性质的树称为二叉树:空树或节点最多有两个子树,称为左子树、右子树, 左右子树节点同样最多有两个子树。二叉树是递归定义的,因而常用递归/DFS的思想处理二叉树相关问题,例如LeetCode题目 104. Maximum Depth of Binary Tree: // 104. Maximum Depth of Binary Tree int maxDepth(Tre...

weixin_39780962的博客 455
上一篇: 树、二叉树的前中后层序遍历(递归、非递归Java实现)
下一篇: LeetCode 有关树深度、路径的题目(JAVA代码实现)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值