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

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

题目描述

给定两个整数数组 preorderinorder ,其中 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
  • preorderinorder无重复 元素
  • inorder 均出现在 preorder
  • preorder 保证 为二叉树的前序遍历序列
  • inorder 保证 为二叉树的中序遍历序列

思路分析

利用先序(根→左→右)和中序(左→根→右)遍历特性:

  1. 先序首元素为根节点;
  2. 中序中根节点左侧是左子树、右侧是右子树;
  3. 递归拆分左右子树的先序 / 中序区间,构建子树。通过值→索引映射表快速定位根节点在中序的位置,避免遍历,提升效率。

代码实现

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

// 辅助函数:递归构建二叉树
struct TreeNode* build(int* preorder, int preStart, int preEnd, 
                       int* inorder, int inStart, int inEnd, 
                       int* indexMap) {
    // 递归终止条件:序列为空
    if (preStart > preEnd || inStart > inEnd) {
        return NULL;
    }
    
    // 先序序列第一个元素是根节点
    int rootVal = preorder[preStart];
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    root->val = rootVal;
    root->left = NULL;
    root->right = NULL;
    
    // 找到根节点在中序序列中的索引
    int rootIndex = indexMap[rootVal + 3000]; // 偏移3000处理负数
    // 左子树的节点个数
    int leftSize = rootIndex - inStart;
    
    // 递归构建左子树
    root->left = build(preorder, preStart + 1, preStart + leftSize,
                       inorder, inStart, rootIndex - 1, indexMap);
    // 递归构建右子树
    root->right = build(preorder, preStart + leftSize + 1, preEnd,
                        inorder, rootIndex + 1, inEnd, indexMap);
    
    return root;
}

struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize) {
    // 构建值到索引的映射表(处理-3000~3000的范围)
    int indexMap[6001] = {0}; // 6001 = 3000 - (-3000) + 1
    for (int i = 0; i < inorderSize; i++) {
        indexMap[inorder[i] + 3000] = i;
    }
    
    // 递归构建二叉树
    return build(preorder, 0, preorderSize - 1, inorder, 0, inorderSize - 1, indexMap);
}

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

题目描述

给定两个整数数组 inorderpostorder ,其中 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
  • inorderpostorder 都由 不同 的值组成
  • postorder 中每一个值都在 inorder
  • inorder 保证是树的中序遍历
  • postorder 保证是树的后序遍历

思路分析

利用后序(左→右→根)和中序(左→根→右)遍历特性:

  1. 后序尾元素为根节点;
  2. 中序中根节点左侧是左子树、右侧是右子树;
  3. 递归拆分左右子树的中序 / 后序区间,构建子树。同样用值→索引映射表快速定位根节点,优化查找效率。

代码实现

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

// 辅助递归函数:构建二叉树
struct TreeNode* build(int* inorder, int inStart, int inEnd,
                       int* postorder, int postStart, int postEnd,
                       int* indexMap) {
    // 递归终止条件:序列无节点
    if (inStart > inEnd || postStart > postEnd) {
        return NULL;
    }
    
    // 后序序列最后一个元素是根节点
    int rootVal = postorder[postEnd];
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    root->val = rootVal;
    root->left = NULL;
    root->right = NULL;
    
    // 找到根节点在中序序列中的索引
    int rootIndex = indexMap[rootVal + 3000]; // 偏移3000处理负数
    // 左子树的节点个数
    int leftSize = rootIndex - inStart;
    
    // 递归构建左子树
    root->left = build(inorder, inStart, rootIndex - 1,
                       postorder, postStart, postStart + leftSize - 1,
                       indexMap);
    // 递归构建右子树
    root->right = build(inorder, rootIndex + 1, inEnd,
                        postorder, postStart + leftSize, postEnd - 1,
                        indexMap);
    
    return root;
}

struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize) {
    // 构建值到中序索引的映射表(处理-3000~3000的范围)
    int indexMap[6001] = {0}; // 6001 = 3000 - (-3000) + 1
    for (int i = 0; i < inorderSize; i++) {
        indexMap[inorder[i] + 3000] = i;
    }
    
    // 递归构建二叉树
    return build(inorder, 0, inorderSize - 1,
                 postorder, 0, postorderSize - 1,
                 indexMap);
}

总结

两类问题核心逻辑一致:

  1. 从遍历序列中定位根节点(先序首 / 后序尾);
  2. 借助中序拆分左右子树区间;
  3. 递归构建子树,映射表优化根节点查找,时间复杂度 O (n),空间复杂度 O (n)。差异仅在于根节点位置和后序序列的区间拆分规则,核心是利用遍历特性拆分递归区间。
相关推荐
灵感__idea7 小时前
Hello 算法:众里寻她千“百度”
前端·javascript·算法
Wect16 小时前
LeetCode 130. 被围绕的区域:两种解法详解(BFS/DFS)
前端·算法·typescript
NAGNIP1 天前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
颜酱2 天前
单调栈:从模板到实战
javascript·后端·算法
CoovallyAIHub2 天前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
强化学习凭什么比监督学习更聪明?RL的“聪明”并非来自算法,而是因为它学会了“挑食”
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
YOLO-IOD深度解析:打破实时增量目标检测的三重知识冲突
深度学习·算法·计算机视觉
NAGNIP2 天前
轻松搞懂全连接神经网络结构!
人工智能·算法·面试