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

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,也就是叶节点链接的nullptrif (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,也就是叶节点链接的nullptrif (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.lryc.cn/news/521324.html

相关文章:

  • 使用sqlplus的easy connect时如何指定是链接到shared server还是dedicated process
  • ubuntu22.4 ROS2 安装gazebo(环境变量配置)
  • 【机器学习:十四、TensorFlow与PyTorch的对比分析】
  • [C++]类与对象(上)
  • 大数据技术实训:Zookeeper集群配置
  • HTML5 加载动画(Loading Animation)
  • C语言进阶-2指针(一)
  • 【人工智能】用Python进行对象检测:从OpenCV到YOLO的全面指南
  • 《深度剖析算法优化:提升效率与精度的秘诀》
  • Mysql--重点篇--索引(索引分类,Hash和B-tree索引,聚簇和非聚簇索引,回表查询,覆盖索引,索引工作原理,索引失效,索引创建原则等)
  • matlab使用 BP 神经网络进行数据预测的完整流程,包括数据读取、数据预处理等等
  • systemd-networkd NetworkManager 介绍
  • 本地部署项目管理工具 Leantime 并实现外部访问
  • PHP cURL 函数初学者完全指南
  • C#中的Array数组,List集合和ArrayList集合--07
  • 基于深度学习的视觉检测小项目(十三) 资源文件的生成和调用
  • 硬件实用技巧:TPS54331DR横杠标识识别1引脚
  • 《C++11》nullptr介绍:从NULL说起
  • 自然语言处理基础:全面概述
  • 网络安全的几种攻击方法
  • 国内源快速在线安装qt5.15以上版本。(10min安装好)(图文教程)
  • 【pycharm发现找不到python打包工具,且无法下载】
  • C++ QT 自绘表盘
  • 数据科学与数据工程:两者的区别与交集
  • MAC AndroidStudio模拟器无网络
  • PHP语言的多线程编程
  • 当自动包布机遇上Profinet转ModbusTCP网关,“妙啊”,工业智能“前景无限
  • 浅析大语言模型安全和隐私保护国内外标准和政策
  • OpenCV相机标定与3D重建(54)解决透视 n 点问题(Perspective-n-Point, PnP)函数solvePnP()的使用
  • Chatper 4: Implementing a GPT model from Scratch To Generate Text