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

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)。差异仅在于根节点位置和后序序列的区间拆分规则,核心是利用遍历特性拆分递归区间。
相关推荐
今天你TLE了吗2 小时前
LeeCode Hot100随机链表的复制 java易懂题解
java·数据结构·链表
山峰哥2 小时前
现代 C++ 的最佳实践:从语法糖到工程化思维的全维度探索
java·大数据·开发语言·数据结构·c++
CoderYanger2 小时前
动态规划算法-两个数组的dp(含字符串数组):43.不同的子序列
java·算法·leetcode·动态规划·1024程序员节
Xの哲學2 小时前
Linux I3C驱动深度剖析: 从原理到实战的全面解析
linux·服务器·算法·架构·边缘计算
爱喝热水的呀哈喽2 小时前
chns方程 推导简单的能量耗散律,分部积分向量形式,sav初简介
算法
代码游侠2 小时前
应用——统计文件字符数、单词数、行数
服务器·笔记·算法
岁岁的O泡奶3 小时前
NSSCTF_crypto_[MTCTF 2021 final]ezRSA
经验分享·python·算法·密码学·crypto
别动哪条鱼3 小时前
FFmpeg AVFormatContext 分配函数详解
数据结构·ffmpeg·音视频
CoderYanger3 小时前
C.滑动窗口-求子数组个数-越短越合法——LCP 68. 美观的花束
java·开发语言·数据结构·算法·leetcode