当前位置: 首页 > 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. 从中序与后序遍历序列构造二叉树

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

http://www.xdnf.cn/news/220969.html

相关文章:

  • USB 网卡——RNDIS 介绍
  • 数据资产:价值的源泉与释放之道
  • Langchain组件
  • 高级前端面试题:基于2025年最新技术体系
  • TS学习指南
  • 人工智能和机器学习在包装仿真中的应用与价值
  • MQTT - Android MQTT 编码实战(MQTT 客户端创建、MQTT 客户端事件、MQTT 客户端连接配置、MQTT 客户端主题)
  • Python列表全面解析:从基础到高阶操作
  • 域名转移:什么是转移码/EPP码/授权码?
  • 基于蓝耘MaaS平台进行api调用创建本地智能ai
  • 代码随想录第39天|leetcode198.打家劫舍、leetcode213.打家劫舍II 、leetcode337.打家劫舍III
  • 4月29日日记
  • 【浙江大学DeepSeek公开课】DeepSeek的本地化部署与AI通识教育之未来
  • 高等数学-第七版-下册 选做记录 习题9-5
  • 【记】Laya2.x数字末尾导致换行异常问题
  • Promtail+Loki+Grafana监控日志
  • AD系列:Windows Server 2025 搭建AD域控和初始化
  • 一文读懂 JavaScript 中的深浅拷贝
  • IEC61499编程方式与传统PLC编程方式比较
  • 生态修复项目管理软件
  • RPCRT4!NdrpEmbeddedPointerMemorySize函数分析之第二次循环
  • 应急演练考试排查-WebSever03
  • P5633 最小度限制生成树
  • Linux环境变量以及进程虚拟地址原理
  • DVWA靶场保姆级通关教程---02命令注入
  • 5.4.2 MVVM例2-用户控件的使用(水在水管中流动的实例)
  • 路径规划算法总结:从 Dijkstra 到 A* 与 Hybrid A
  • GUI_DrawPixel 函数详解
  • BalenaEtcher 2.1镜像烧录工具软件下载及安装教程
  • Vite性能优化指南 ✅