代码随想录二刷 | 二叉树 | 从中序与后序遍历序列构造二叉树

代码随想录二刷 | 二叉树 | 从中序与后序遍历序列构造二叉树

  • 题目描述
  • 解题思路
  • 代码实现

题目描述

106.从中序与后序遍历序列构造二叉树

给定两个整数数组 inorder 和 postorder ,其中 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 保证是树的后序遍历

解题思路

根据两个顺序构建二叉树,注意三个点:

  • 第一,前序遍历为中左右,中序遍历为左右中,后序遍历是左右中;
  • 第二,后序遍历的最后一个元素一定是根节点;
  • 第三,前序数组、中序数组、后序数组的大小是相等的。

找到根节点后再根据每个遍历的特点,就能在纸上很轻松地还原出二叉树。

这里使用递归一步一步拆分:

  • 第一步:如果数组大小为0,说明为空节点
    if (postorder.size() == 0) return NULL;
    
  • 第二步:如果不为空,那么取后序数组的最后一个节点为根节点
    int rootValue = postorder[postorder.size() - 1];
    TreeNode* root = new TreeNode(rootValue);
    // 如果root就是叶子节点,也就是说这是一个只有根节点的二叉树,直接返回root
    if (postorder.size() == 1) return root;
    
  • 第三步:找到根节点在中序数组的位置,作为拆分点
    int delimiterIndex;
    for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;
    }
    
  • 第四步:拆分中序数组,左边为中序左数组,右边为中序右数组,(中序遍历为左右中)
    // 左闭右开区间 [0, delimiterIndex)
    vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
    // [delimeterIndex, end)
    vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end())
    
  • 第五步:拆分后序数组,拆成后序左数组和后序右数组(后序遍历为左右中)
    // 因为后序数组没有很明显的拆分点,但它的长度是和中序数组相等的,对应的根节点的左右子树的长度也是相等的,所以可以根据中序左数组的大小作为拆分点来拆分,拆分成后序左数组和后序右数组。
    // 舍弃末尾元素,因为这个元素已经是根节点了,我们拆分出来的实际是根节点的左右子树,所以先去掉它
    postorder.resize(postorder.size() - 1);
    // 左闭右开,使用中序左数组的长度作为拆分点 [0, leftInorder.size())
    vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size())
    // [leftInorder.size(), end)
    vector<int> rightPostorder(postorder.begin() + leftInorder.size() + 1, postorder.end());
    
  • 第六步,递归处理左数组和有数组
    root->left = traversal(leftInorder, leftPostorder);
    root->left = traversal(rightInorder, rightPostorder);
    return root;
    

代码实现

class Solution {
private:TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {// 空节点,返回NULLif (postorder.size() == 0) return NULL;// 后序数组的最后一个元素为根节点int rootValue = postorder.size() - 1;TreeNode* root = new TreeNode(rootValue); // 根节点为叶子节点,返回rootif (postorder.size() == 1) return root;// 找到中序遍数组的拆分点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 切割中序数组// [0, delimiterIndex)vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);// [delimiterIndex + 1, end)vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());// postorder 去掉末尾元素	postorder.resize(postorder.size() - 1);// 拆分后序数组// [0, leftInorder.size())vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());// [leftInorder,size(), end)// 没有 + 1的原因是,虽然是左闭右开,但是已经将根节点剔除了vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());// 递归左右数组root->left = traversal(leftInorder, leftPostorder);root->right = traversal(rightInorder, rightPostorder);return root;}
public:TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {if (inorder.size() == 0 || postorder.size() == 0) return NULL;return ttraversal(inorder, postorder);}
};

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【案例】注册表简介,新建一个右键菜单打开方式选项

这里写目录标题 来源注册表的介绍注册表编辑器VScode的打开方式菜单![image-20231217201730121](https://img-blog.csdnimg.cn/img_convert/56c02643df9e8ec3afb4f3ac5cc0cdd5.png)如何自定义一个右键菜单备份注册表新建一个菜单选项”右键用记事本打开“ DWORDQWORD可扩充字符…

【动态规划】06路径问题_不同路径II_C++(medium)

题目链接&#xff1a;leetcode不同路径II 目录 题目解析&#xff1a; 算法原理 1.状态表示 2.状态转移方程 3.初始化 4.填表顺序 5.返回值 编写代码 题目解析&#xff1a; 题目让我们求在考虑网格中有障碍物的情况下&#xff0c;从左上角到右下角将会有多少条不同的路径…

QT第一步

文章目录 软件下载软件安装QT的程序组新建项目 软件下载 qt下载网址&#xff1a;https://download.qt.io/archive/qt/   关于版本&#xff1a;     我选择的版本是5.14.2&#xff0c;这个版本是最后的二进制安装包的版本&#xff0c;在往后的版本就需要在线安装了。并且5…

python学习,1.变量和简单的数据类型

一、编写文章的目的 1.这是为了初学者而写的&#xff0c;学习python比较简单然后上手&#xff0c;也会过滤一些&#xff0c;如果没有提起到的&#xff0c;可以在学习的时候进行补充 2.相对来说&#xff0c;上手难度不会很难。 二、内容 1.让首字母大写&#xff1b;字母都大写…

【每日一题】2697. 字典序最小回文串-2023.12.13

题目&#xff1a; 2697. 字典序最小回文串 给你一个由 小写英文字母 组成的字符串 s &#xff0c;你可以对其执行一些操作。在一步操作中&#xff0c;你可以用其他小写英文字母 替换 s 中的一个字符。 请你执行 尽可能少的操作 &#xff0c;使 s 变成一个 回文串 。如果执行…

计算机中msvcr120.dll丢失怎样修复,这5个方法可以搞定

几乎在所有操作系统中&#xff0c;可分为两种库&#xff0c;一种是静态库&#xff08;.lib&#xff09;&#xff0c;另一种是动态库&#xff08;.dll&#xff09;。 为什么很多小伙伴在打开软件的时候会弹出“由于找不到XXX.dll文件&#xff0c;无法继续执行代码、、、、、、”…

Vue学习计划-Vue2--VueCLi(四)组件传值和自定义事件

1. 组件传值 组件化编码流程&#xff1a; 拆分静态组件&#xff1a;组件要按照功能点拆分&#xff0c;命名不要与html元素冲突实现动态组件&#xff1a;考虑好数据的存放位置&#xff0c;数据是一个组件在用&#xff0c;还是一些组件在用&#xff1a; 一个组件在用&#xff0c…

《点云处理》 提取点云内点和外点

前言 关于内点&#xff08;inliers&#xff09;和外点&#xff08;outliers&#xff09;在点云处理方向上是个非常常见的名词。有时候&#xff0c;内点也会被称之为有效点&#xff0c;而外点会被称之为无效点。所谓有效和无效都是相对而言的&#xff0c;无效不一定是真的没有意…

BAQ压缩原理

什么是BAQ? BAQ——Block Adaptive Quantization,块自适应量化 BAQ是一种数据压缩算法。 谁提出了BAQ压缩? BAQ压缩原理是由美国NASA JPL的R. Kwok和W.T.K. Johnson在1989年提出的。第一次被用于美国NASA的“麦哲伦金星探测”任务中。 BAQ压缩的目的是什么? 上世纪后半…

面试 Java 算法高频题五问五答第一期

面试 Java 算法高频题五问五答第一期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;括号生成: 数字 n 代表生成括号的对数&#xff0c;请你设计一个…

动态规划——OJ题(一)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、第N个泰波那契数1、题目讲解2、思路讲解3、代码实现 二、三步问题1、题目讲解2、思路讲解…

数据结构与算法—哈希表

哈希表 文章目录 哈希表1. 问题引出2. 基本介绍3. 应用实例 1. 问题引出 看一个实际需求&#xff0c;google公司的一个上机题:有一个公司&#xff0c;当有新的员工来报道时&#xff0c;要求将该员工的信息加入(id,性别&#xff0c;年龄等)&#xff0c;当输入该员工的id时&#…