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

LeetCode105_从先序与中序遍历序列构造二叉树

LeetCode105_从先序与中序遍历序列构造二叉树

  • 标签:#树 #数组 #哈希表 #分治 #二叉树
    • Ⅰ. 题目
    • Ⅱ. 示例
  • 0. 个人方法
  • 官方题解二:迭代

标签:#树 #数组 #哈希表 #分治 #二叉树

Ⅰ. 题目

给定两个整数数组 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]

0. 个人方法

  • 先序:即(根、左、右)的排列方式;
  • 中序:即(左、根、右)的排列方式。

Q:要构造这颗二叉树,肯定要进行完整的遍历,那该如何遍历呢?
A:根结点肯定是一个重要的结点,我们可以以根结点为起点,通过递归,不断对左右子树进行搜索,并返回根结点,逐步构建成这颗二叉树。

  1. 首先观察先序遍历:根结点始终在最前面(这很好,方便我们递归时对根结点的操作),但是左、右子树的边界在先序中不明显,那怎么办呢?
  2. 这时我们再观察中序遍历:中序遍历中,根结点把左右子树分开了,所以我们可以通过在先序中得到的根结点,在中序遍历中找到它,这样就有左右子树的长度了,也可以返回去用到先序遍历中了。
  3. 递归:观察完先序和中序后,递归的写法就很明了了。题目只给了调用两个根结点的函数,这显然是不够用的,因为我们要对左右子树进行操作,所以先定义一个新函数,在新函数中进行递归。
/*** Definition for a binary tree node.* 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) {}* };*/
class Solution {
public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {return buildTreeRoot(preorder, 0, preorder.size()-1, inorder,  0, inorder.size()-1);}TreeNode* buildTreeRoot(vector<int>& preorder, int preStart, int preEnd,vector<int>& inorder,  int inStart,  int inEnd){// 0. 先写递归停止的条件if (preStart > preEnd || inStart > inEnd){return nullptr;}// 1. 从根结点开始,判断左右子树区间TreeNode* root = new TreeNode(preorder[preStart]);// 2. 找到中序遍历中的根结点int mid = 0;for (int i=inStart; i<=inEnd; i++){if (inorder[i] == preorder[preStart]){mid = i;break;}}// 3. 左子树的大小int leftsize = mid - inStart;root->left = buildTreeRoot(preorder, preStart+1, preStart+leftsize, inorder,  inStart,  mid-1);root->right = buildTreeRoot(preorder, preStart+leftsize+1, preEnd, inorder,  mid+1, inEnd);return root;}
};
  • 复杂度分析

    • 时间复杂度:O(n),其中 n 是树中的节点个数。

    • 空间复杂度:O(n),除去返回的答案需要的 O(n) 空间之外,我们还需要使用 O(n) 的空间存储哈希映射,以及 O(h)(其中 h 是树的高度)的空间表示递归时栈空间。这里 h<n,所以总空间复杂度为 O(n)。

官方题解二:迭代

  • 迭代法是一种非常巧妙的实现方法。

  • 对于前序遍历中的任意两个连续节点 u 和 v,根据前序遍历的流程,我们可以知道 u 和 v 只有两种可能的关系:

    • v 是 u 的左儿子。这是因为在遍历到 u 之后,下一个遍历的节点就是 u 的左儿子,即 v;

    • u 没有左儿子,并且 v 是 u 的某个祖先节点(或者 u 本身)的右儿子。如果 u 没有左儿子,那么下一个遍历的节点就是 u 的右儿子。如果 u 没有右儿子,我们就会向上回溯,直到遇到第一个有右儿子(且 u 不在它的右儿子的子树中)的节点 u_a,那么 v 就是 u_a 的右儿子。

class Solution {
public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {if (!preorder.size()) {return nullptr;}TreeNode* root = new TreeNode(preorder[0]);stack<TreeNode*> stk;stk.push(root);int inorderIndex = 0;for (int i = 1; i < preorder.size(); ++i) {int preorderVal = preorder[i];TreeNode* node = stk.top();if (node->val != inorder[inorderIndex]) {node->left = new TreeNode(preorderVal);stk.push(node->left);}else {while (!stk.empty() && stk.top()->val == inorder[inorderIndex]) {node = stk.top();stk.pop();++inorderIndex;}node->right = new TreeNode(preorderVal);stk.push(node->right);}}return root;}
};
http://www.xdnf.cn/news/330859.html

相关文章:

  • 如何从路由表优化的角度理解[CIDR]无类别域间路由选择技术?
  • 六级阅读---2024.12 卷一 仔细阅读1
  • 【编译原理】第五章 自下而上语法分析
  • 快速上手SpringBoot开发指南
  • 力扣热题100之反转链表
  • Linux系统Shell脚本之shell数组、正则表达式、及AWK
  • Mongo3.4升级到mongo6性能降低9倍
  • HSV颜色空间
  • 51camera将参加第九届沥青路面论坛暨新技术新成果展示会
  • 代码随想录算法训练营第三十三天(补)
  • Unity Gizmos
  • 题解 洛谷 Luogu P1073 [NOIP 2009 提高组] 最优贸易 强连通分量 Tarjan 缩点 拓扑排序 动态规划 C++
  • Vue与Python的深度整合:构建现代Web应用的全栈范式
  • 国标GB28181设备管理软件EasyGBS打造明厨亮灶食品安全监管防线
  • 对称二叉树(简单)
  • sqlite数据库操作
  • Qt开发:枚举的介绍和使用
  • 【Win】插入u盘/固态硬盘Hub不显示在我的电脑
  • ModuleNotFoundError: No module named ‘numpy.typing‘
  • oracle 优化器
  • 【DB2】DB2启动失败报错SQL1042C
  • 深入解析进程间通信与Socket原理:从理论到TypeScript实战
  • 一文详解极大似然估计,从极大似然估计的角度理解线性回归
  • 101alpha_第4个
  • Linux系统之Shell脚本:for、while循环及脚本实操
  • 优艾智合CEO张朝辉荣膺U45杰出青年企业家
  • 强化学习环境安装——openAI gym
  • Chain-of-Draft (CoD) 是提示工程的新王者
  • openstack的网络
  • 数据结构--树