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

从遍历序列构造二叉树:前序+中序与中序+后序的递归解法详解

文章目录

    • 1. 问题背景
    • 2. 核心思路
    • 3. 从前序与中序遍历序列构造二叉树
      • 3.1 递归分治思路
      • 3.2 代码实现与注释
    • 4. 从中序与后序遍历序列构造二叉树
      • 4.1 递归分治思路
      • 4.2 代码实现与注释
    • 5. 复杂度分析
    • 6. 总结

1. 问题背景

二叉树的遍历方式包括前序(根-左-右)、中序(左-根-右)和后序(左-右-根)。给定其中两种遍历序列,能否唯一确定一棵二叉树的结构?

  • 前序+中序:可以唯一确定二叉树。
  • 中序+后序:可以唯一确定二叉树。
  • 前序+后序:无法唯一确定(存在多种可能性)。

本文详细讲解如何通过 前序+中序中序+后序 两种组合构造二叉树。


2. 核心思路

两种问题的解法均基于 递归分治,核心步骤如下:

  1. 确定根节点

    • 前序序列的第一个元素为根节点。
    • 后序序列的最后一个元素为根节点。
  2. 分割左右子树

    • 利用根节点在中序序列中的位置,将中序序列分割为左子树和右子树。
    • 根据中序序列的左右子树长度,确定前序或后序序列的子树区间。
  3. 递归构建子树

    • 对左子树和右子树重复上述过程,直到无法分割。

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

3.1 递归分治思路

  • 根节点:前序序列的起始元素 preorder[preStart]
  • 中序分割:根据根节点在中序序列中的位置 rootIndex,分割左子树和右子树。
  • 前序分割
    • 左子树的前序区间:preStart + 1preStart + leftSubtreeSize
    • 右子树的前序区间:preStart + leftSubtreeSize + 1preEnd

3.2 代码实现与注释

class Solution {public TreeNode buildTree(int[] preorder, int[] inorder) {// 哈希表存储中序序列的值与索引,便于快速查找根节点位置Map<Integer, Integer> inorderMap = new HashMap<>();for (int i = 0; i < inorder.length; i++) {inorderMap.put(inorder[i], i);}return buildTreeHelper(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1, inorderMap);}private TreeNode buildTreeHelper(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd, Map<Integer, Integer> inorderMap) {// 终止条件:区间无效时返回nullif (preStart > preEnd || inStart > inEnd) return null;// 根节点为前序序列的起始元素int rootVal = preorder[preStart];TreeNode root = new TreeNode(rootVal);// 获取根节点在中序序列中的位置int rootIndex = inorderMap.get(rootVal);int leftSubtreeSize = rootIndex - inStart; // 左子树节点数量// 递归构建左子树root.left = buildTreeHelper(preorder, preStart + 1,                   // 左子树前序起始preStart + leftSubtreeSize,     // 左子树前序结束inorder, inStart,                        // 左子树中序起始rootIndex - 1,                  // 左子树中序结束inorderMap);// 递归构建右子树root.right = buildTreeHelper(preorder, preStart + leftSubtreeSize + 1, // 右子树前序起始preEnd,                         // 右子树前序结束inorder, rootIndex + 1,                  // 右子树中序起始inEnd,                          // 右子树中序结束inorderMap);return root;}
}

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

4.1 递归分治思路

  • 根节点:后序序列的末尾元素 postorder[postEnd]
  • 中序分割:根据根节点在中序序列中的位置 rootIndex,分割左子树和右子树。
  • 后序分割
    • 左子树的后序区间:postStartpostStart + leftSubtreeSize - 1
    • 右子树的后序区间:postStart + leftSubtreeSizepostEnd - 1

4.2 代码实现与注释

class Solution {public TreeNode buildTree(int[] inorder, int[] postorder) {// 哈希表存储中序序列的值与索引Map<Integer, Integer> inorderMap = new HashMap<>();for (int i = 0; i < inorder.length; i++) {inorderMap.put(inorder[i], i);}return buildTreeHelper(postorder, 0, postorder.length - 1, inorder, 0, inorder.length - 1, inorderMap);}private TreeNode buildTreeHelper(int[] postorder, int postStart, int postEnd,int[] inorder, int inStart, int inEnd,Map<Integer, Integer> inorderMap) {// 终止条件:区间无效时返回nullif (postStart > postEnd || inStart > inEnd) return null;// 根节点为后序序列的末尾元素int rootVal = postorder[postEnd];TreeNode root = new TreeNode(rootVal);// 获取根节点在中序序列中的位置int rootIndex = inorderMap.get(rootVal);int leftSubtreeSize = rootIndex - inStart; // 左子树节点数量// 递归构建左子树root.left = buildTreeHelper(postorder, postStart,                          // 左子树后序起始postStart + leftSubtreeSize - 1,     // 左子树后序结束inorder, inStart,                             // 左子树中序起始rootIndex - 1,                       // 左子树中序结束inorderMap);// 递归构建右子树root.right = buildTreeHelper(postorder, postStart + leftSubtreeSize,         // 右子树后序起始postEnd - 1,                         // 右子树后序结束(排除根节点)inorder, rootIndex + 1,                      // 右子树中序起始inEnd,                              // 右子树中序结束inorderMap);return root;}
}

5. 复杂度分析

  • 时间复杂度:O(n)
    每个节点被访问一次,哈希表查询操作 O(1)。
  • 空间复杂度:O(n)
    哈希表存储中序序列 O(n),递归栈深度在最坏情况下为 O(n)(树退化为链表)。

6. 总结

  1. 核心共性

    • 通过根节点分割中序序列,确定左右子树的区间。
    • 递归处理左右子树时,需精准计算前序或后序序列的子树区间。
  2. 关键区别

    • 根节点位置:前序序列首元素 vs. 后序序列末元素。
    • 区间计算:前序需跳过根节点后分割,后序需排除末元素后分割。
  3. 扩展思考

    • 如何验证构建的二叉树是否正确?
      重新生成前序/中序/后序遍历序列,与原输入比对。
    • 如果遍历序列中存在重复值,上述方法是否有效?
      无效,因为哈希表无法唯一确定根节点位置。

题目链接

  • 105. 从前序与中序遍历序列构造二叉树
  • 106. 从中序与后序遍历序列构造二叉树

通过系统化的递归分治思想,可以高效解决二叉树构造问题。理解区间分割的数学逻辑是掌握此类问题的关键!

相关文章:

  • JavaScript面试问题
  • tbb parallel_for 使用
  • 颜色分类,不靠“调色盘”:双指针 VS 计数排序的正面PK
  • 【Linux】服务自启动设置的方式
  • LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding
  • Java之BigDecimal
  • Silvaco仿真中victory process的蒙特卡洛(Monte Carlo)离子注入
  • 深入理解 Linux 权限管理:从基础到进阶
  • 【GESP】C++三级练习 luogu-B2117 整理药名
  • (三十二)Android开发中AppCompatActivity和Activity之间的详细区别
  • 2025运维工程师面试题1(答案在后一张)
  • 企业的AI转型:生死时速的进化之路
  • 【题解-Acwing】870. 约数个数
  • k8s部署
  • 4.29【Q】paraCompute
  • python之数字类型的操作
  • 无人机航拍羊只检测数据集VOC+YOLO格式6065张1类别
  • vue3使用<el-date-picker分别设置开始时间和结束时间时,设置开始时间晚于当前时间,开始时间早于结束时间,结束时间晚于开始时间
  • python:练习:2
  • 双重差分模型学习笔记(理论)
  • 韩国下届大选执政党初选4进2结果揭晓,金文洙、韩东勋胜出
  • 4月人文社科联合书单|天文学家的椅子
  • 打造全域消费场景,上海大世界百个演艺娱乐新物种待孵化
  • 证券时报:“好房子”标准即将全面落地,购房者有哪些新期待
  • 加拿大今日大选:房价、印度移民和特朗普,年轻人在焦虑什么?
  • 上海质子重离子医院已收治8000例患者,基本覆盖国内常见恶性肿瘤