0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Offer系列面试题0:重建二叉树

算法与数据结构 来源:图解面试算法 2020-07-09 15:03 次阅读

今天分享的题目来源于 LeetCode 上的剑指 Offer 系列面试题07. 重建二叉树,近半年在微软面试环节出现过 2 次,属于中高难度的算法题!

一、题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出

前序遍历preorder=[3,9,20,15,7] 中序遍历inorder=[9,3,15,20,7]

返回如下的二叉树:

3 / 920 / 157

限制:

0 <= 节点个数 <= 5000

二、题目解析

首先,我们先来复习一下前序遍历、中序遍历。(在下方的视频中分布讲解)

前序遍历

二叉树的前序遍历顺序是:根节点、左子树、右子树,每个子树的遍历顺序同样满足前序遍历顺序。

中序遍历

二叉树的中序遍历顺序是:左子树、根节点、右子树,每个子树的遍历顺序同样满足中序遍历顺序。

复习过后,我们可以得出以下结论:

在二叉树的前序遍历序列中,第一个数字总是树的根结点的值;

在二叉树的中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边

以本题的序列为例,前序遍历序列的第一个数字 3 就是根结点的值,在中序遍历序列,找到根结点值的位置。根据中序遍历特点,在根结点的值 3前面的数字都是左子树结点的值,在根结点的值 3后面的数字都是右子树结点的值。

二叉树很重要的一个性质是递归,在找到了左子树、右子树的前序遍历序列和中序遍历序列后,我们可以按照同样的方法去确定子左子树和子右子树的构建。

具体的代码编写思路如下(来源于 Krahets's Blog):

递推参数:前序遍历中根节点的索引pre_root_idx、中序遍历左边界in_left_idx、中序遍历右边界in_right_idx。

终止条件:当in_left_idx > in_right_idx,子树中序遍历为空,说明已经越过叶子节点,此时返回 null 。

递推工作:

建立根节点 root :值为前序遍历中索引为pre_root_idx的节点值。

搜索根节点 root 在中序遍历的索引 i :为了提升搜索效率,本题解使用哈希表map预存储中序遍历的值与索引的映射关系,每次搜索的时间复杂度为 O(1)。

构建根节点root的左子树和右子树:通过调用 recursive()方法开启下一层递归。

左子树:根节点索引为 pre_root_idx + 1 ,中序遍历的左右边界分别为 in_left_idx 和 i - 1。

右子树:根节点索引为 i - in_left_idx + pre_root_idx + 1(即:根节点索引 + 左子树长度 + 1),中序遍历的左右边界分别为 i + 1 和 in_right_idx。

返回值:返回root,含义是当前递归层级建立的根节点root为上一递归层级的根节点的左或右子节点。

三、动画描述

四、图片描述

五、参考代码

classSolution{ //在中序序列中查找与前序序列首结点相同元素的时候,如果使用while循环去一个个找效率很慢 //这里我们借助数据结构HashMap来辅助查找,在开始递归之前把所有的中序序列的元素和它们所在的下标存到一个map中,这样查找的时间复杂度是O(logn) HashMapmap=newHashMap<>(); //保留的前序遍历 int[]preorder; publicTreeNodebuildTree(int[]preorder,int[]inorder){ this.preorder=preorder; //在开始递归之前把所有的中序序列的元素和它们所在的下标存到一个map中 for(inti=0;i< preorder.length; i++) {             map.put(inorder[i], i);         }         //二叉树的重要性质是递归         return recursive(0,0,inorder.length-1);     }     /** 根据前序遍历序列和中序遍历序列重新组建二叉树      * @param pre_root_idx 前序遍历的索引      * @param in_left_idx  中序遍历左边界的索引      * @param in_right_idx 中序遍历右边界的索引      */     public TreeNode recursive(int pre_root_idx, int in_left_idx, int in_right_idx) {         //子树中序遍历为空,说明已经越过叶子节点,此时返回 nul         if (in_left_idx >in_right_idx){ returnnull; } //root_idx是在前序里面的 TreeNoderoot=newTreeNode(preorder[pre_root_idx]); //通过map,根据前序的根节点的值,在中序中获取当前根的索引 intidx=map.get(preorder[pre_root_idx]); //左子树的根节点就是左子树的(前序遍历)第一个,就是+1,左边边界就是left,右边边界是中间区分的idx-1 root.left=recursive(pre_root_idx+1,in_left_idx,idx-1); //右子树的根,就是右子树(前序遍历)的第一个,就是当前根节点加上左子树的数量 root.right=recursive(pre_root_idx+(idx-1-in_left_idx+1)+1,idx+1,in_right_idx); returnroot; } }

这段代码的一个难点就是root.left与root.right,我这里抽离出来详细解释一下。

1、root.left

2、root.right

六、复杂度分析

时间复杂度

时间复杂度为 O(N)。

空间复杂度

空间复杂度为 O(N)。

七、相关标签

递归

哈希表

八、参考来源

1、https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/mian-shi-ti-07-zhong-jian-er-cha-shu-di-gui-fa-qin/ 题解区

2、https://krahets.gitee.io/views/sword-for-offer/2020-02-24-sword-for-offer-07.html

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数字
    +关注

    关注

    1

    文章

    1693

    浏览量

    51296
  • 二叉树
    +关注

    关注

    0

    文章

    74

    浏览量

    12322

原文标题:面试字节跳动时,我竟然遇到了原题……

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Redis使用重要的两个机制:Reids持久化和主从复制

    持久化的,也就是说要先存储到磁盘上嘛,这样才方便主从之间的数据同步。 此外,因为Redis 主从复制的原理也是后端面试必考知识点,所以先送上一份福利【77道redis高频面试题汇总(带答案)】,面试用到率85%! 部分内容展示:
    的头像 发表于 12-18 10:33 43次阅读
    Redis使用重要的两个机制:Reids持久化和主从复制

    面试题】人工智能工程师高频面试题汇总:机器学习深化篇(题目+答案)

    ,或者深度学习的框架,还有怎么优化模型,这些都是加分项,能有效提高面试通过率。本篇小编整理了一些高频的机器学习深化方面的面试题,这些题目都是从实际面试中总结出来的,非
    的头像 发表于 12-16 13:42 457次阅读
    【<b class='flag-5'>面试题</b>】人工智能工程师高频<b class='flag-5'>面试题</b>汇总:机器学习深化篇(题目+答案)

    面试题】人工智能工程师高频面试题汇总:Transformer篇(题目+答案)

    随着人工智能技术的突飞猛进,AI工程师成为了众多求职者梦寐以求的职业。想要拿下这份工作,面试的时候得展示出你不仅技术过硬,还得能解决问题。所以,提前准备一些面试常问的问题,比如机器学习的那些算法
    的头像 发表于 12-13 15:06 381次阅读
    【<b class='flag-5'>面试题</b>】人工智能工程师高频<b class='flag-5'>面试题</b>汇总:Transformer篇(题目+答案)

    人工智能工程师高频面试题汇总——机器学习篇

    ,或者深度学习的框架,还有怎么优化模型,这些都是加分项,能有效提高面试通过率。本篇小编整理了一些高频的机器学习方面的面试题,这些题目都是从实际面试中总结出来的,非常具
    的头像 发表于 12-04 17:00 799次阅读
    人工智能工程师高频<b class='flag-5'>面试题</b>汇总——机器学习篇

    什么是默克尔(Merkle Tree)?如何计算默克尔根?

    01 默克尔的概念 默克尔(Merkle Tree)是一种特殊的二叉树,它的每个节点都存储了一个数据块的哈希值。哈希值是一种可以将任意长度的数据转换为固定长度的字符串的算法,它具有唯一性和不可
    的头像 发表于 09-30 18:22 767次阅读
    什么是默克尔<b class='flag-5'>树</b>(Merkle Tree)?如何计算默克尔根?

    面试嵌入式工作,会被问什么问题?

    面试嵌入式工作时,面试官可能会从多个方面考察应聘者的知识、技能和经验。以下是一些常见的嵌入式工作面试问题,这些问题涵盖了基础知识、专业技能、项目经验和个人能力等方面
    的头像 发表于 07-17 09:26 1974次阅读
    <b class='flag-5'>面试</b>嵌入式工作,会被问什么问题?

    指电极上覆盖敏感材料的阻值计算

    覆盖的敏感材料厚度超出指厚度时计算电阻,是否可以视作指电极指间电阻多个周期串联后与超出指厚度部分敏感材料电阻并联
    发表于 07-05 14:48

    指MOSFET器件静电防护鲁棒性提升技巧

    栅极接地NMOS是一种广泛应用的片上ESD器件结构,为达到特定ESD防护等级,一般会采用多指版图形式来减小器件占用的芯片面积。但是,多指栅极接地NMOS在ESD应力作用下,各个指难于做到均匀
    的头像 发表于 06-22 00:50 507次阅读
    多<b class='flag-5'>叉</b>指MOSFET器件静电防护鲁棒性提升技巧

    大厂电子工程师常见面试题#电子工程师 #硬件工程师 #电路知识 #面试题

    电子工程师电路
    安泰小课堂
    发布于 :2024年04月30日 17:33:15

    哈夫曼编码怎么算 哈夫曼编码左边是0还是1

    二叉树,将出现频率高的字符用较短的编码表示,而出现频率低的字符则用较长的编码表示。通过这种方式,可以实现对数据进行高效的编码和解码。 下面我们将详细介绍哈夫曼编码的算法过程。 统计字符频率 在进行哈夫曼编码前,首先需
    的头像 发表于 01-30 11:27 2823次阅读

    MCP251X can驱动移植nuc980采样用设备配置时,中断如何配置设备?

    MCP251X can驱动移植nuc980 采样用设备配置时,中断如何配置设备? spi0: spi@b0061000 { status = \"okay\"
    发表于 01-17 06:43

    什么是守护线程?守护线程的底层原理和使用示例

    大家好,今天这篇文章来梳理一下有关守护线程的相关问题,这也是之前曾经有被问到过的面试题,在此之前我们先看一看守护线程的使用示例。
    的头像 发表于 01-05 11:01 1404次阅读
    什么是守护线程?守护线程的底层原理和使用示例

    工业上常见的高精度主动式重建算法

    三维重建目前是最为炙手可热的领域。摄影测量或结构光投影技术可以解决漫反射重建问题,但却无法有效应对镜面反射物体(如玻璃、积水、反光物体和汽车车身)等的重建挑战。
    发表于 01-05 10:46 475次阅读
    工业上常见的高精度主动式<b class='flag-5'>重建</b>算法

    经典Linux面试题总结

    绝对路径用什么符号表示?当前目录、上层目录用什么表示?主目录用什么表示? 切换目录用什么命令?
    的头像 发表于 01-04 11:01 362次阅读

    总结常见电路面试题

    输入信号应提前时钟上升沿(如上升沿有效)T时间到达芯片,这个T就是建立时间-Setup time。如不满足setup time,这个数据就不能被这一时钟打入触发器,只有在下一个时钟上升沿,数据才能被打入触发器。
    的头像 发表于 01-02 16:03 411次阅读