Leetcode:106. 从中序与后序遍历序列构造二叉树、105. 从前序与中序遍历序列构造二叉树(C++)

news2024/11/28 8:08:37

目录

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

问题描述:

 实现代码与解析:

切割法(递归):

原理思路:

索引版本:

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

问题描述:

实现代码与解析:

切割法(递归):

原理思路:

索引版本:


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]

 实现代码与解析:

切割法(递归):

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) 
    {
        //若为空树
        if(postorder.size()==0)
        {
            return NULL;//返回NULL,最后的叶子结点左右子树都为空
        }
        int rootValue=postorder[postorder.size()-1];//后序最后一个元素       
        TreeNode* root=new TreeNode(rootValue);//后序遍历的第一个结点为根结点
        //叶子结点
        if(postorder.size()==1) return root;
        int index;//中序切割点
        //寻找切割点
        for(index=0;index<inorder.size();index++)
        {
            if(inorder[index]==rootValue) break;
        }
        //切割中序数组
        vector<int> leftInorder(inorder.begin(),inorder.begin()+index);
        vector<int> rightInorder(inorder.begin()+index+1,inorder.end());
        postorder.pop_back();//去除后序最后一个元素
        //切割后序数组
        vector<int> leftPostorder(postorder.begin(),postorder.begin()+leftInorder.size());
        vector<int> rightPostorder(postorder.begin()+leftInorder.size(),postorder.end());
        root->left=buildTree(leftInorder,leftPostorder);
        root->right=buildTree(rightInorder,rightPostorder);
        return root;
    }
};

原理思路:

        用中序和后序、中序和前序构造二叉树是数据结构中的一种经典题型,如果只是画出二叉树的图像,大家应该是都会的,这里介绍一些如何用代码来还原二叉树。

        1、首先写递归的终止条件,判断后序数组是否为空,若为空,说明该树是空树,直接返回NULL,同时也解决了递归式时有一侧子树为空的空结点可以返回。

//若为空树
if(postorder.size()==0)
{
    return NULL;//返回NULL,最后的叶子结点左右子树都为空
}

        2、判断是否进入到了叶子结点,也就是后序数组只剩下一个数,返回此结点,去掉此代码也是可以的,因为我们前面有了遇到空结点时返回的代码,遇到叶子结点再向下递归一层到空结点返回也是可以的。

//叶子结点
if(postorder.size()==1) return root;

        3、然后我们就记录后序数组最后一个元素来寻找切割点了,把中序数组切割成左中序和右中序,然后再根据左中序大小,将后序数组切成左后序和右后序,注意在切割后序数组前把后序数组最后一个数去掉,因为我们这层已经用过这个结点值了,还有注意切割的左右是开还是闭,切割中序和后序时最好保持统一。

//切割中序数组
vector<int> leftInorder(inorder.begin(),inorder.begin()+index);
vector<int> rightInorder(inorder.begin()+index+1,inorder.end());
postorder.pop_back();//去除后序最后一个元素
//切割后序数组
vector<int> leftPostorder(postorder.begin(),postorder.begin()+leftInorder.size());
vector<int> rightPostorder(postorder.begin()+leftInorder.size(),postorder.end());

        4、递归同时进行结点的连接,左子树传入左中序和左后序,右子树传入右中序和右后序。

root->left=buildTree(leftInorder,leftPostorder);
root->right=buildTree(rightInorder,rightPostorder);

        还有另一种写法,就是每次递归时多传入切割的中序区间的索引,后序区间的索引的参数。这样就不用我们每次递归时在单独创建vector了,减少了空间,不过原理是相同的,下面给出:

索引版本:

class Solution {
private:
    TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) 
    {
        if (postorderBegin == postorderEnd) return NULL;
        int rootValue = postorder[postorderEnd - 1];
        TreeNode* root = new TreeNode(rootValue);
        if (postorderEnd - postorderBegin == 1) return root;
        int Index;//中序切割点
        for (Index = inorderBegin; Index < inorderEnd;Index++) 
        {
            if (inorder[Index] == rootValue) break;
        }
        // 切割中序数组
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = Index;
        int rightInorderBegin = Index + 1;
        int rightInorderEnd = inorderEnd;
        // 切割后序数组
        int leftPostorderBegin =  postorderBegin;
        int leftPostorderEnd = postorderBegin + (Index - inorderBegin); 
        int rightPostorderBegin = postorderBegin + (Index - inorderBegin);
        int rightPostorderEnd = postorderEnd - 1; // 去除最后一个元素
        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  postorder, leftPostorderBegin, leftPostorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
        return root;
    }
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};

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]

实现代码与解析:

切割法(递归):

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
    {
        if(preorder.size()==0) return NULL;
        int rootValue=preorder[0];
        TreeNode* root=new TreeNode(rootValue);
        //叶子结点
        if(preorder.size()==1) return root;
        int index;//切割点
        for(index=0;index<inorder.size();index++)
        {
            if(rootValue==inorder[index]) break;
        }
        //切割中序数组
        vector<int> leftInorder(inorder.begin(),inorder.begin()+index);
        vector<int> rightInorder(inorder.begin()+index+1,inorder.end());
        //切割前序数组
        preorder.erase(preorder.begin());//去除第一个元素,已经使用过了
        vector<int> leftPreorder(preorder.begin(),preorder.begin()+leftInorder.size());
        vector<int> rightPreorder(preorder.begin()+leftInorder.size(),preorder.end());
        root->left=buildTree(leftPreorder,leftInorder);
        root->right=buildTree(rightPreorder,rightInorder);
        return root;
        
    }
};

原理思路:

        此题与上一题原理相同,就不详细解释了,还是给出索引版本的代码:

索引版本:

class Solution {
private:
        TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
        if (preorderBegin == preorderEnd) return NULL;
        int rootValue = preorder[preorderBegin]; 
        TreeNode* root = new TreeNode(rootValue);
        if (preorderEnd - preorderBegin == 1) return root;
        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) 
        {
            if (inorder[delimiterIndex] == rootValue) break;
        }
        // 切割中序数组
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;
        // 切割前序数组
        int leftPreorderBegin =  preorderBegin + 1;
        int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin; 
        int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex - inorderBegin);
        int rightPreorderEnd = preorderEnd;
        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  preorder, leftPreorderBegin, leftPreorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, preorder, rightPreorderBegin, rightPreorderEnd);
        return root;
    }
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
    {    
        return traversal(inorder, 0, inorder.size(), preorder, 0, preorder.size());
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

zookeeper单节点部署

kafkazookeeper单节点部署及注意事项 事前准备&#xff1a; 1、一台Linux服务器或者是一台虚拟机 2、准备好JDK环境 3、安装好wget&#xff08;当然也可以不用这个&#xff0c;只是用于下载安装包的一个工具&#xff0c;所以能下载好包就是没问题的&#xff09; 4、需要了解vim…

Java面试题每日10问(4)

Core Java - OOPs Concepts: Inheritance Interview Questions 1. Why use inheritance in java? For Method Overriding (so runtime polymorphism can be achieved).For Code Reusability. Terms used in Inheritance Class: –A class is a group of objects which have c…

皕杰报表点击导出按钮后网页变空白问题

有人反映使用皕杰报表导出时&#xff0c;点击导出按钮后网页变成了空白&#xff0c;然后就没有反应了。看tomcat控制台也没有错误信息&#xff0c;似乎遇到了一个很难缠的问题&#xff0c;没有错误信息却卡滞了&#xff0c;这个问题怎么解决呢&#xff1f; 还是要从tomcat的日志…

盘点微服务架构下的诸多身份验证方式

联合作者&#xff1a;罗泽轩&#xff0c;API7.ai 技术专家、Apache APISIX PMC 成员 联合作者&#xff1a;赵士瑞&#xff0c;API7.ai 技术工程师&#xff0c;Apache APISIX Committer 身份认证是授予用户访问系统并授予使用系统的必要权限的过程。而提供了这一功能的服务&…

指针详解——高级指针的解析及应用

目录 &#x1f411;指针的初步了解 &#x1f402;指针的深入认识 &#x1f99b;1.指针数组 &#x1f400;指针数组的介绍 &#x1f400;指针数组的用法介绍 &#x1f42b;2.数组指针 &#x1f98c;数组指针的介绍以及使用 &#x1f9ae;3.函数指针 &#x1f408;函数指针的介绍…

Linux0基础入门:初识shell脚本编程

初识脚本编程到目前为止我们已经知道了 Linux 系统和命令行的基础知识&#xff0c;是时候开始编程了。本章讨论编写 shell 脚本的基础知识。在开始编写自己的 shell 脚本大作前&#xff0c;你必须了解这些基本概念。 使用多个命令到目前为止&#xff0c;你已经了解了如何使用 s…

Revit连接处理:阳台扶手和楼梯扶手,墙和梁

一、Revit中阳台扶手和楼梯扶手的连接处理 如图&#xff0c;有一些阳台扶手和楼梯扶手连接的地方&#xff0c;连接处需要进行处理。 1.在楼板合适的边缘处先画出楼梯 (1)单击“楼梯” (2)在楼梯类型属性对话框中修改楼梯属性 (3)绘制楼梯 为了定位方便、准确&#xff0c;首先要…

重塑底层逻辑,涅槃重生继续远航

背景介绍 从贫困县爬出来本硕均为211学校&#xff0c;在机械专业学习7年&#xff0c;有4年的时间热衷于编程学习。因此一路跨行到IT行业。 履历介绍 从毕业后一直在AI算法行业研究&#xff0c;呆过初创公司&#xff0c;目前在上市公司上班。尝尽IT的苦也吃过IT的甜。从毕业一…

【jQuery】常用API——jQuery效果

jQuery 给我们封装了很多动画效果&#xff0c;最为常见的如下&#xff1a;一、显示隐藏切换效果1. 显示语法规范 show([speed,[easing],[fn]]);显示参数&#xff1a;&#xff08;1&#xff09;参数都可以省略&#xff0c; 无动画直接显示。&#xff08;2&#xff09;speed&…

el-date-picker日期时间组件 报 placement 警告的解决方法

在使用el-date-picker组件时报这个警告&#xff0c;虽然不影响页面&#xff0c;但一打开页面跳出来一堆错误警告&#xff0c;实在受不了 解决办法&#xff1a;加上以下一行即可

无序字母对 -- 欧拉回路

洛谷&#xff1a;P1341 无序字母对题目描述前置知识欧拉路径定义判断是否为欧拉图思路code参考题目描述 题目描述 给定 n 个各不相同的无序字母对&#xff08;区分大小写&#xff0c;无序即字母对中的两个字母可以位置颠倒&#xff09;。请构造一个有 (n1) 个字母的字符串使得每…

同源、跨域的概念与实现

本文将结合周老师的讲义对同源与跨域这一前端经典问题进行系统的总结、整理。一起来坐牢&#xff0c;快&#xff01; 1. 同源限制 1.1 历史背景 - 含义的转变 1995年&#xff0c;同源政策由 Netscape 公司引入浏览器。目前&#xff0c;所有浏览器都实行这个政策。 最初&…

爬虫代理Scrapy框架详细介绍4

Scrapy 框架 Scrapy实例 下载安装 pip install scrapy Hello World 创建工程 在 cmd 下切换到想创建 scrapy 项目的地方&#xff0c;然后使用命名 scrapy startproject tutorial 注&#xff1a;tutorial 为工程名 然后就会发现在当前位置会多出一个文件夹&#xff0c;名字是 tu…

C++——map|set介绍

目录 关联式容器 set set的构造 set的迭代器 set的容量 set修改操作 equal_range multiset map map的构造 map的迭代器 map的容量与元素访问 map测试 关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、…

Linux内核权限提升漏洞

SSRF检测的一些思考 DNS平台没有立刻收到请求&#xff0c;是在之后的某个时间段收到了不同的请求信息&#xff0c;这至少表明了一点&#xff0c;此处存在有无回显的SSRF&#xff0c;虽然想要证明有更大的危害比较困难&#xff0c;但是至少说明了存在有SSRF的风险&#xff0c;所…

Maven 命令之将本地 Jar 包安装到 Maven 本地仓库

1、前言 Maven 是 Java 平台下的一款项目构建和依赖管理的自动化管理工具。 通过 Maven 远程仓库地址我们可以方便的管理 Jar 依赖包&#xff0c;但是在实际项目中有时候存在远程仓库中没有的 Jar 包&#xff0c;我们在项目中又必须要使用它&#xff0c;那就需要把本地 Jar 添…

HC-SR04超声波传感器使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、关于HC-SR04二、使用步骤1.确保驱动已经安装2.安装GPIO工具3.安装GPIO的Python支持4.Python3代码总结前言 最近在做一个项目&#xff0c;需要用到超声波传感…

誉辰智能拟科创板上市:欲募资4亿元,毛利率、研发费用率均下滑

近日&#xff0c;深圳市誉辰智能装备股份有限公司&#xff08;下称“誉辰智能”&#xff09;在上海证券交易所更新招股书&#xff08;申报稿&#xff09;&#xff0c;披露时间为2023年1月7日&#xff0c;准备在科创板上市。据贝多财经了解&#xff0c;誉辰智能曾于2022年6月29日…

解决SpringBoot项目整合Sharding-JDBC后启动慢的问题

一、问题描述线上某一项目以jar包的方式发布&#xff0c;需要健康检查&#xff0c;若15次健康检查页面状态均为非200则健康检查失败&#xff0c;就会导致tomcat服务加载失败。前几天版本迭代&#xff0c;发布该项目时&#xff0c;因最后一次健康检查的时间比启动完成时早&#…

练习时长两年半的tcp三次握手

1、TCP是什么&#xff1f;TCP是面向连接的协议&#xff0c;它基于运输连接来传送TCP报文段&#xff0c;TCP运输连接的建立和释放&#xff0c;是每一次面向连接的通信中必不可少的过程。TCP运输连接有以下三个阶段&#xff1a;建立TCP连接&#xff0c;也就是通过三报文握手来建立…