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

2024-01-19 09:38

本文主要是介绍面试字节跳动时,我竟然遇到了原题……,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

来源:图解面试算法

今天分享的题目来源于 LeetCode 上的剑指 Offer 系列 面试题07. 重建二叉树,近半年在字节跳动算法面试环节出现过高达 14 次,你很可能遇到过,它属于中高难度的算法题,今天吴师兄和你一起弄懂!

题目链接:

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/

一、题目描述

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

例如,给出

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

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

限制:

0 <= 节点个数 <= 5000

二、题目解析

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

前序遍历

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

中序遍历

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

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

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

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

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

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

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

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

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

  • 递推工作:

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

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

  3. 构建根节点 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 为上一递归层级的根节点的左或右子节点。

三、动画描述

四、图片描述

五、参考代码

class Solution {//在中序序列中查找与前序序列首结点相同元素的时候,如果使用 while 循环去一个个找效率很慢//这里我们借助数据结构 HashMap 来辅助查找,在开始递归之前把所有的中序序列的元素和它们所在的下标存到一个 map 中,这样查找的时间复杂度是 O(logn)HashMap<Integer, Integer> map = new HashMap<>();//保留的前序遍历int[] preorder;public TreeNode buildTree(int[] preorder, int[] inorder) {this.preorder = preorder;//在开始递归之前把所有的中序序列的元素和它们所在的下标存到一个 map 中for (int i = 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) {//子树中序遍历为空,说明已经越过叶子节点,此时返回 nulif (in_left_idx > in_right_idx) {return null;}//root_idx是在前序里面的TreeNode root = new TreeNode(preorder[pre_root_idx]);// 通过 map ,根据前序的根节点的值,在中序中获取当前根的索引int idx = map.get(preorder[pre_root_idx]);//左子树的根节点就是 左子树的(前序遍历)第一个,就是 +1 ,左边边界就是 left ,右边边界是中间区分的idx-1root.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);return root;}
}

这段代码的一个难点就是 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

我知道你在看

这篇关于面试字节跳动时,我竟然遇到了原题……的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/622012

相关文章

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.

Jackson库进行JSON 序列化时遇到了无限递归(Infinite Recursion)的问题及解决方案

《Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursion)的问题及解决方案》使用Jackson库进行JSON序列化时遇到了无限递归(InfiniteRecursi... 目录解决方案‌1. 使用 @jsonIgnore 忽略一个方向的引用2. 使用 @JsonManagedR

在MySQL执行UPDATE语句时遇到的错误1175的解决方案

《在MySQL执行UPDATE语句时遇到的错误1175的解决方案》MySQL安全更新模式(SafeUpdateMode)限制了UPDATE和DELETE操作,要求使用WHERE子句时必须基于主键或索引... mysql 中遇到的 Error Code: 1175 是由于启用了 安全更新模式(Safe Upd

解决JavaWeb-file.isDirectory()遇到的坑问题

《解决JavaWeb-file.isDirectory()遇到的坑问题》JavaWeb开发中,使用`file.isDirectory()`判断路径是否为文件夹时,需要特别注意:该方法只能判断已存在的文... 目录Jahttp://www.chinasem.cnvaWeb-file.isDirectory()遇

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

mysql主从及遇到的问题解决

《mysql主从及遇到的问题解决》本文详细介绍了如何使用Docker配置MySQL主从复制,首先创建了两个文件夹并分别配置了`my.cnf`文件,通过执行脚本启动容器并配置好主从关系,文中还提到了一些... 目录mysql主从及遇到问题解决遇到的问题说明总结mysql主从及遇到问题解决1.基于mysql

.NET利用C#字节流动态操作Excel文件

《.NET利用C#字节流动态操作Excel文件》在.NET开发中,通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据,本文将演示如何在.NET平台使用C#通过字节流创建,读取,编辑及保... 目录用C#创建并保存Excel工作簿为字节流用C#通过字节流直接读取Excel文件数据用C#通过字节

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

Anaconda 中遇到CondaHTTPError: HTTP 404 NOT FOUND for url的问题及解决办法

最近在跑一个开源项目遇到了以下问题,查了很多资料都大(抄)同(来)小(抄)异(去)的,解决不了根本问题,费了很大的劲终于得以解决,记录如下: 1、问题及过程: (myenv) D:\Workspace\python\XXXXX>conda install python=3.6.13 Solving environment: done.....Proceed ([y]/n)? yDownloa