每日一练:LeeCode-106、从中序与后序遍历序列构造⼆叉树、LeeCode-106、从前序与中序遍历序列构造二叉树【二叉树+DFS+分治】

本文是力扣LeeCode-106、从中序与后序遍历序列构造二叉树 LeeCode-105、从前序与中序遍历序列构造二叉树 学习与理解过程,本文仅做学习之用,对本题感兴趣的小伙伴可以出门左拐LeeCode。

106、从中序与后序遍历序列构造⼆叉树

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

示例 1:
在这里插入图片描述

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

示例 2:
输入:inorder = [-1], postorder = [-1]
输出:[-1]

提示:

  • 1 <= inorder.length <= 3000
  • postorder.length == inorder.length
  • -3000 <= inorder[i], postorder[i] <= 3000
  • inorder 和 postorder 都由 不同 的值组成
  • postorder 中每一个值都在 inorder 中
  • inorder 保证是树的中序遍历
  • postorder 保证是树的后序遍历

思路

1. 判断是否为分治问题
原问题定义为从 postorder 和 inorder 构建二叉树,是一个典型的分治问题

  • 问题可以分解:从分治的角度切入我们可以将原问题划分为两个子问题构建左子树、构建右子树
  • 加上一步操作初始化根节点。而对于每棵子树(子问题),我们仍然可以复用以上划分方法,将其划分为更小的子树(子问题),直至达到最小子问题(空子树)时终止
  • 子问题是独立的左子树和右子树是相互独立的,它们之间没有交集。在构建左子树时,我们只需关注中序遍历和前序遍历中与左子树对应的部分。右子树同理
  • 子问题的解可以合并:一旦得到了左子树和右子树(子问题的解),我们就可以将它们链接到根节点上得到原问题的解

2. 如何划分子树
根据以上分析,这道题可以使用分治来求解,但如何通过后序遍历 postorder 和中序遍历 inorder 来划分左子树和右子树呢
根据定义,postorderinorder 都可以划分为三个部分。
后序遍历:[ 左子树 | 右子树 | 根节点] ,例如上图的树对应 [ 9 | 15 7 20 | 3 ] 。
中序遍历:[ 左子树 | 根节点 | 右子树 ] ,例如上图的树对应 [ 9 | 3 | 15 20 7 ] 。
所以根据上述定义,我们可以通过从后往前遍历后序遍历的数组拿到遍历的值作为根节点去切割中序遍历数组
比如:拿到3,可以将中序数组切割为 [ 9 | 3 | 15 20 7 ]

3. 基于变量描述子树区间
根据以上划分方法,我们已经得到根节点、左子树、右子树在 postorder和 inorder 中的索引区间。而为了描述这些索引区间,我们需要借助几个指针变量

  • 当前树的根节点在 postorder中的索引记为 postRootIndex
  • 当前树的根节点在 inorder 中的索引记为m
  • 当前树在 inorder 中的索引区间记为 [indexLeft, indexRight] ,这个区间会随着切割inorder后变化

代码实现

class Solution {
    private int postRootIndex = 0;  //当前树的根节点在 postorder中的索引
    private HashMap<Integer, Integer> inorderMap = new HashMap<>();
    private int[] gInorder;
    private int[] gPostorder;
    public TreeNode buildTree(int[] inorder, int[] postorder) {

        gInorder = inorder;
        gPostorder = postorder;
        int length = gPostorder.length;
        postRootIndex = length-1;
        // 初始化哈希表,存储 inorder 元素到索引的映射,避免重复遍历inorder
        for(int i=0;i<inorder.length;i++){
            inorderMap.put(inorder[i],i);
        }
        return dfs(0,length-1);
    }
    TreeNode dfs(int indexLeft,int indexRight){
        // 子树区间为空时终止
        if(indexLeft>indexRight)return null;

        int rootValue = gPostorder[postRootIndex];
        postRootIndex--;
        // 初始化根节点
        TreeNode root = new TreeNode(rootValue);
        // 查询 m ,从而划分左右子树,当前树的根节点在 inorder 中的索引
        int m = inorderMap.get(rootValue);
		//先构建左子树,还是右子树,需要根据提供的后序或者前序数组中节点的值的排列顺序决定
		//比如:此题是后序遍历,从后往前遍历postOrder,并生成节点,所以是: 中、右、左
        // 子问题:构建右子树
        root.right = dfs(m+1,indexRight);
        // 子问题:构建左子树
        root.left = dfs(indexLeft,m-1);
        return root;
    }
}

注: 先构建左子树,还是右子树,需要根据提供的后序或者前序数组中节点的值的排列顺序决定 比如:此题是后序遍历,从后往前遍历postOrder,并生成节点,所以是: 中、右、左

  • 时间复杂度为 𝑂(𝑛)
  • 空间复杂度为 𝑂(𝑛)

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

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

示例 1:在这里插入图片描述

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

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

提示:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorder 和 inorder 均 无重复 元素
  • inorder 均出现在 preorder
  • preorder 保证 为二叉树的前序遍历序列
  • inorder 保证 为二叉树的中序遍历序列

思路

此题和106的解题思路是一致的,但是需要注意
先构建左子树,还是右子树,需要根据提供的后序或者前序数组中节点的值的排列顺序决定 比如:此题是前序遍历,从前往后遍历preOrder,并生成节点,所以是: 中、左、右

代码实现

class Solution {
    private int preRootIndex = 0;   //当前树的根节点在 preorder中的索引
    private HashMap<Integer, Integer> inorderMap = new HashMap<>();
    private int[] gInorder;
    private int[] gPreorder;
    public TreeNode buildTree(int[] preorder, int[] inorder) {

        gInorder = inorder;
        gPreorder = preorder;
        int length = gPreorder.length;
        // 初始化哈希表,存储 inorder 元素到索引的映射,避免重复遍历inorder
        for(int i=0;i<inorder.length;i++){
            inorderMap.put(inorder[i],i);
        }
        return dfs(0,length-1);
    }
    TreeNode dfs(int indexLeft,int indexRight){
        // 子树区间为空时终止
        if(indexLeft>indexRight)return null;

        int rootValue = gPreorder[preRootIndex];
        preRootIndex++;
        // 初始化根节点
        TreeNode root = new TreeNode(rootValue);
        // 查询 m ,从而划分左右子树,当前树的根节点在 inorder 中的索引
        int m = inorderMap.get(rootValue);
        // 子问题:构建左子树
        root.left = dfs(indexLeft,m-1);
        // 子问题:构建右子树
        root.right = dfs(m+1,indexRight);
        return root;
    }
}
  • 时间复杂度为 𝑂(𝑛)
  • 空间复杂度为 𝑂(𝑛)

最重要的一句话:做二叉树的题目,首先需要确认的是遍历顺序
大佬们有更好的方法,请不吝赐教,谢谢

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaScript 】finally() 方法和Filter() 方法

JavaScript 中的finally() 方法 finally是 JavaScript 构造中使用的方法try-catch。try它在and阻塞之后执行catch&#xff0c;无论 Promise 是已履行还是已拒绝。该函数的主要作用是执行必要的清理任务并向用户传达消息。一个常见的用例可能是通知用户“您的请求已被处理”&am…

C# OpenVino Yolov8 Pose

目录 效果 模型信息 项目 代码 下载 效果 模型信息 Model Properties ------------------------- date&#xff1a;2023-09-07T17:11:43.091306 description&#xff1a;Ultralytics YOLOv8n-pose model trained on /usr/src/app/ultralytics/datasets/coco-pose.yaml a…

93 log4j-slf4j-impl 搭配上 log4j-to-slf4j 导致的 StackOverflow

前言 呵呵 最近想要 做一个 mongo 低版本的客户端读取高版本的服务端传递过来的数据造成的一个错误的时候, 出现了这样的问题 引入了 mongo-java-driver 之后, 使用相关 api 的时候会触发 com.mongo.internal.connection.BaseCluser 的初始化, 其依赖的 Loggers 间接的依赖…

MyBatisPlus之分页查询及Service接口运用

一、分页查询 1.1 基本分页查询 配置分页查询拦截器 package com.fox.mp.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springfra…

分享86个表单按钮JS特效,总有一款适合您

分享86个表单按钮JS特效&#xff0c;总有一款适合您 86个表单按钮JS特效下载链接&#xff1a;https://pan.baidu.com/s/1WwQGFPWv8464JBcuEMJZ_Q?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;…

SpringBoot3整合Mybatis-Plus,自定义动态数据源starter

文章目录 前言正文一、项目总览二、核心代码展示2.1 自定义AbstractRoutingDataSource2.2 动态数据源DynamicDataSource2.3 动态数据源自动配置2.4 动态数据源上下文DynamicDataSourceContextHolder2.5 动态数据源修改注解定义2.6 修改切面DynamicDataSourceAspect2.7 动态数据…

嵌入式系统的前景:未来智能汽车

&#xff08;本文为简单介绍&#xff0c;个人的观点仅供参考&#xff09; 智能汽车时代已经来临!未来十年,我们的汽车将变得越来越智能化。各大汽车公司在研发自动驾驶技术,目标是实现真正的无人驾驶。要实现这一目标,嵌入式系统将发挥关键作用。 简单来说,嵌入式系统就是在汽…

【Linux】指令提权-sudo

Hello everybody&#xff0c;新年快乐&#xff01;哈哈&#xff01;今天打算给大家讲讲指令提权的相关知识&#xff0c;虽然内容不多&#xff0c;但有时却很有用。在我们学习过权限&#xff0c;vim后就可以学习指令提权啦&#xff0c;没看过的宝子们建议先去看一看我之前的文章…

旅游|基于Springboot的旅游管理系统设计与实现(源码+数据库+文档)

旅游管理系统目录 目录 基于Springboot的旅游管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户管理 2、景点分类管理 3、景点信息管理 4、酒店信息管理 5、景点信息 6、游记分享管理 四、数据库设计 1、实体ER图 2、具体的表设计如下所示&#xf…

工业级加固平板丨亿道三防平板电脑丨安卓工业平板丨改善车队管理

在现代物流和运输行业中&#xff0c;车队管理是一个复杂而重要的任务。为了更好地管理车队&#xff0c;提高工作效率和减少成本&#xff0c;许多企业正在采用新技术和工具。其中&#xff0c;三防平板电脑作为一种功能强大且适应恶劣环境的设备&#xff0c;已经在车队管理中得到…

【九章斩题录】Leetcode:判定是否互为字符重排(C/C++)

面试题 01.02. 判定是否互为字符重排 ✅ 模板&#xff1a;C class Solution { public:bool CheckPermutation(string s1, string s2) {} }; 「 法一 」排序 &#x1f4a1; 思路&#xff1a;看到题目中说 "重新排列后能否变成另一个字符串"&#xff0c;等等……重新…

第三百一十七回

文章目录 1. 概念介绍2. 实现方法2.1 hintText2.2 labelText2.3 controller 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何在输入框中处理光标"相关的内容&#xff0c;本章回中将介绍如何添加输入框默认值.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1.…

[VulnHub靶机渗透] Misdirection: 1

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

Linux操作系统基础(八):Linux的vi/vim编辑器

文章目录 Linux的vi/vim编辑器 一、vi/vim编辑器介绍 二、打开文件 三、VIM编辑器的三种模式(重点) 四、命令模式相关命令 五、底行模式相关命令 Linux的vi/vim编辑器 一、vi/vim编辑器介绍 vi是visual interface的简称, 是Linux中最经典的文本编辑器 vi的核心设计思想…

专业130+总分410+苏州大学837信号系统与数字逻辑考研经验电子信息与通信,真题,大纲,参考书

今年考研总分410&#xff0c;专业837信号系统与数字逻辑130&#xff0c;整体每门相对比较均衡&#xff0c;没有明显的短板&#xff0c;顺利上岸苏大&#xff0c;总结一下自己这大半年的复习经历&#xff0c;希望可以对大家有所帮助&#xff0c;也算是对自己考研做个总结。 专业…

6 scala-面向对象编程基础

Scala 跟 Java 一样&#xff0c;是一门面向对象编程的语言&#xff0c;有类和对象的概念。 1 类与对象 与 Java 一样&#xff0c;Scala 也是通过关键字 class 来定义类&#xff0c;使用关键字 new 创建对象。 要运行我们编写的代码&#xff0c;同样像 Java 一样&#xff0c;…

烟火可禁却难禁,灵境难及终将及

现实痛点 2024年1月30日&#xff0c;贵阳市发生了一件令人痛心的事&#xff0c;有人在小区内放烟花导致失火&#xff0c;一男子具备足够的消防安全知识&#xff0c;知道如何使用消防栓却因设施不合格接不上消防栓&#xff0c;接上了又没水&#xff0c;消防员来也束手无策&…

#Z2322. 买保险

一.题目 二.思路 1.暴力 训练的时候&#xff0c;初看这道题&#xff0c;这不就打个暴力吗&#xff1f; 2.暴力代码 #include<bits/stdc.h> #define int long long using namespace std; int n,m,fa,x,y,vis[1000001],ans; vector<int> vec[1000001]; void dfs(i…

VitePress-14- 配置-titleTemplate 的作用详解

作用描述 1、titleTemplate 是标题的后缀&#xff1b;2、可以自定义标题的后缀&#xff1b;3、可以自定义整个的标题以及后缀&#xff0c;语法如下&#xff1a; titleTemplate: :title 链接符号 自己定义的后缀 【:title】&#xff1a;从页面的第一个 <h1> 标题推断出的…

Qt视频播放器项目

一.创建项目 二.设计UI 按钮与名称的对应 打开视频按钮 -> pushButton_Open 播放按钮 -> pushButton_Play 暂停按钮 -> pushButton_Pause 停止按钮 -> pushButton_Stop 音量按钮 -> pushButton_Sound设置图标 在项目目录下创建images文件夹&#xff0c;把图标…
最新文章