当前位置: 首页 > article >正文

LeetCode 热题 100_从前序与中序遍历序列构造二叉树(47_105_中等_C++)(二叉树;递归)

LeetCode 热题 100_从前序与中序遍历序列构造二叉树(47_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 保证 为二叉树的中序遍历序列

题解:

解题思路:

思路一(递归):

1、分析中序遍历和先序遍历的特点:
先序遍历:根 左 右
中序遍历: 左 根 右

① 我们可以通过先序遍历第一个结点来确定当前的根节点。
② 通过preorder和inorder均无重复元素,则可通过当前的根节点唯一确定中序遍历中当前根节点的位置,从而将中序遍历序列划分为左 根 右三个区间。
③ 通过中序遍历划分的左 根 右三个区间,就可以将先序序列的左右区间也划分出来。
④ 将划分的左右区间分别进行上述过程直至左右区间没有元素为止。
⑤ 我们发现上述是一个递归的过程。
⑥ 通过先序遍历第一个元素查找其在中序遍历中的位置是很耗费时间的,我们可以建立一个哈希表来存储中序遍历元素值和下标的对应关系,这样便能节省查找的时间。

2、复杂度分析:
① 时间复杂度:O(n),n代表前序遍历或中序遍历中元素的个数。将中序遍历中的n个数据存入哈希表时间为O(n),将n个元素转换为二叉树O(n)。
② 空间复杂度:O(n),n代表前序遍历或中序遍历中元素的个数。将中序遍历中的n个数据存入哈希表所需空间为O(n),递归创建二叉树最坏的情况下为O(n)。

代码实现

代码实现(思路一(递归)):
class Solution {
private:
    unordered_map<int,int> inorderVal_index;

public:
    
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        //计算先序遍历数组和中序遍历数组的大小,其实这两个是一样的
        int preLen = preorder.size();
        int inLen = inorder.size();

        //将中序遍历的元素和下标的对应关系存储到哈希表中
        for (int i = 0; i < inLen; i++)
        {
            inorderVal_index[inorder[i]]=i;
        }
        //递归的构建二叉树,包含先序和中序数组,和其对应的范围下标
        return myBuildTree(preorder,inorder,0,preLen-1,0,inLen-1);
        
    }

    TreeNode* myBuildTree(vector<int>& preorder, vector<int>& inorder,int preorder_left,int preorder_right,int inorder_left,int inorder_right ){
        //如果区间元素为0则返回nullptr,也就是叶节点链接的nullptr
        if (preorder_left>preorder_right)
        {
            return nullptr;
        }
        //inorder_root代表中序遍历序列中根节点的下标
        int inorder_root=inorderVal_index[preorder[preorder_left]];
        //先序遍历第一个结点就是根节点,创建根节点
        TreeNode *root=new TreeNode(preorder[preorder_left]);

        //通过根在中序遍历的位置确定左区间的大小,从而推出先序遍历的左右区间
        int size_left_subtree=inorder_root-inorder_left;
        //在左子区间递归的进行上述过程
        root->left=myBuildTree(preorder,inorder,preorder_left+1,preorder_left+size_left_subtree,inorder_left,inorder_root-1);
        //在右子区间递归的进行上述过程
        root->right=myBuildTree(preorder,inorder,preorder_left+size_left_subtree+1,preorder_right,inorder_root+1,inorder_right);
        return root;
    }

};
以思路一为例进行调试
#include<iostream>
#include <vector>
#include <unordered_map>
using namespace std;


struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

//中序遍历输出节点的值
void inorder_print(TreeNode *root){
    if (root==nullptr) return ;
    inorder_print(root->left);
    
    if(root!=nullptr){
        cout<<root->val<<" ";
    }else{
        cout<<"null ";
    }
  
    inorder_print(root->right);
}

//方法一:
class Solution {
private:
    unordered_map<int,int> inorderVal_index;

public:
    
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        //计算先序遍历数组和中序遍历数组的大小,其实这两个是一样的
        int preLen = preorder.size();
        int inLen = inorder.size();

        //将中序遍历的元素和下标的对应关系存储到哈希表中
        for (int i = 0; i < inLen; i++)
        {
            inorderVal_index[inorder[i]]=i;
        }
        //递归的构建二叉树,包含先序和中序数组,和其对应的范围下标
        return myBuildTree(preorder,inorder,0,preLen-1,0,inLen-1);
        
    }

    TreeNode* myBuildTree(vector<int>& preorder, vector<int>& inorder,int preorder_left,int preorder_right,int inorder_left,int inorder_right ){
        //如果区间元素为0则返回nullptr,也就是叶节点链接的nullptr
        if (preorder_left>preorder_right)
        {
            return nullptr;
        }
        //inorder_root代表中序遍历序列中根节点的下标
        int inorder_root=inorderVal_index[preorder[preorder_left]];
        //先序遍历第一个结点就是根节点,创建根节点
        TreeNode *root=new TreeNode(preorder[preorder_left]);

        //通过根在中序遍历的位置确定左区间的大小,从而推出先序遍历的左右区间
        int size_left_subtree=inorder_root-inorder_left;
        //在左子区间递归的进行上述过程
        root->left=myBuildTree(preorder,inorder,preorder_left+1,preorder_left+size_left_subtree,inorder_left,inorder_root-1);
        //在右子区间递归的进行上述过程
        root->right=myBuildTree(preorder,inorder,preorder_left+size_left_subtree+1,preorder_right,inorder_root+1,inorder_right);
        return root;
    }

};


int main(int argc, char const *argv[])
{
    //前序遍历和中序遍历
    vector<int> preorder={3,9,20,15,7};
    vector<int> inorder={9,3,15,20,7};

    //通过先序遍历和中序遍历构造二叉树
    Solution s;
    TreeNode *root= s.buildTree(preorder,inorder);

    //中序遍历输出构造的二叉树
    inorder_print(root);
    return 0;
}

LeetCode 热题 100_从前序与中序遍历序列构造二叉树(47_105)原题链接
欢迎大家和我沟通交流(✿◠‿◠)


http://www.kler.cn/a/503869.html

相关文章:

  • 离线docker安装数据库(无法访问互联网),那么直接使用 docker pull mysql:latest
  • ESP32,uart安装驱动uart_driver_install函数剖析,以及intr_alloc_flags 参数的意义
  • C# PDF下载地址转图片(Base64 编码)
  • R语言的数据库编程
  • bochs+gdb调试linux0.11环境搭建
  • 使用 configparser 读取 INI 配置文件
  • AI-ANNE:探索型神经网络——将深度学习模型转移到微控制器和嵌入式系统
  • 【网络云SRE运维开发】2025第2周-每日【2025/01/11】小测-【第11章NAT理论和实操考试】解析和参考
  • 中国地面气候资料日值数据集(V3.0)格式和下载说明
  • 【深度学习】核心概念-数据驱动(Data-Driven)
  • 详解C#的文件写入和读取:从基础到高级应用
  • 初识JAVA-面向对象的三大特征之多态
  • DS1302模块学习笔记
  • 【gin】http方法了解,以及RESTful API与版本控制
  • [IGP]ospf ip frr 快速重路由技术
  • 认识微服务
  • 文本在屏幕上自由游动
  • 求矩阵不靠边元素之和(PTA)C语言
  • 用 Python 处理 CSV 和 Excel 文件
  • 构建云原生后端服务——以Spring Boot + Kubernetes为例
  • 《语言模型的新型推理范式:基于链式思考与强化学习的突破》
  • 量子计算:从薛定谔的猫到你的生活
  • hive知识体系
  • ubuntu22.04安装注意点
  • 力扣 全排列
  • ros2笔记-6.5 使用ros2_control驱动机器人