资讯动态

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

发布时间:2026/10/26 17:10:07 来源:尧图企业网站定制
1. 题目背景与核心问题这道LeetCode hot100题目编号105要求我们根据二叉树的前序遍历和中序遍历序列重建原始的二叉树结构。这是数据结构与算法中非常经典的递归应用问题也是各大技术面试中的高频考点。为什么这个问题如此重要因为在实际开发中我们经常需要序列化和反序列化二叉树结构。比如将内存中的树结构存储到数据库或文件中通过网络传输树形数据缓存复杂的树形配置前序中序的组合之所以能唯一确定一棵二叉树关键在于前序遍历的第一个元素必定是根节点在中序遍历中找到这个根节点左侧就是左子树右侧就是右子树递归应用这个规律就能重建整棵树2. 前序与中序遍历的特性分析2.1 遍历序列的特点前序遍历Preorder的顺序是根节点 → 左子树 → 右子树 中序遍历Inorder的顺序是左子树 → 根节点 → 右子树例如对于二叉树3 / \ 9 20 / \ 15 7其前序遍历为[3,9,20,15,7] 中序遍历为[9,3,15,20,7]2.2 重建二叉树的数学原理为什么这两个序列能唯一确定二叉树关键在于前序序列的第一个元素3就是根节点在中序序列中找到3其左侧[9]就是左子树的中序遍历前序序列中根节点后的相同数量元素[9]就是左子树的前序遍历剩余部分[20,15,7]就是右子树的前序遍历这个性质可以递归应用到子树的重建中。3. 递归解法实现细节3.1 基础递归框架def buildTree(preorder, inorder): if not preorder or not inorder: return None root_val preorder[0] root TreeNode(root_val) root_pos_in_inorder inorder.index(root_val) left_inorder inorder[:root_pos_in_inorder] right_inorder inorder[root_pos_in_inorder1:] left_preorder preorder[1:1len(left_inorder)] right_preorder preorder[1len(left_inorder):] root.left buildTree(left_preorder, left_inorder) root.right buildTree(right_preorder, right_inorder) return root3.2 时间复杂度优化上述解法每次都要在inorder中查找根节点位置最坏情况下时间复杂度是O(n^2)。我们可以用哈希表提前存储中序遍历的值到索引的映射def buildTree(preorder, inorder): inorder_map {val:idx for idx,val in enumerate(inorder)} def helper(pre_start, pre_end, in_start, in_end): if pre_start pre_end: return None root_val preorder[pre_start] root TreeNode(root_val) root_pos inorder_map[root_val] left_size root_pos - in_start root.left helper(pre_start1, pre_startleft_size, in_start, root_pos-1) root.right helper(pre_startleft_size1, pre_end, root_pos1, in_end) return root return helper(0, len(preorder)-1, 0, len(inorder)-1)这样时间复杂度优化到O(n)空间复杂度O(n)用于存储哈希表。4. 迭代解法与实现4.1 迭代法思路递归解法虽然直观但可能面临栈溢出风险。我们可以用迭代法模拟递归过程用栈保存尚未处理右子树的节点用指针跟踪中序遍历的当前位置前序遍历序列指导我们创建节点中序遍历序列告诉我们何时该添加右孩子4.2 迭代法实现def buildTree(preorder, inorder): if not preorder: return None root TreeNode(preorder[0]) stack [root] inorder_idx 0 for i in range(1, len(preorder)): node stack[-1] if node.val ! inorder[inorder_idx]: node.left TreeNode(preorder[i]) stack.append(node.left) else: while stack and stack[-1].val inorder[inorder_idx]: parent stack.pop() inorder_idx 1 parent.right TreeNode(preorder[i]) stack.append(parent.right) return root这种方法的时间复杂度也是O(n)空间复杂度O(n)最坏情况下栈的大小。5. 边界条件与测试用例5.1 必须考虑的边界情况空输入preorder或inorder为空单节点树完全左斜树或右斜树有重复值的树题目通常假设值唯一前序和中序序列不匹配的情况5.2 典型测试用例# 正常情况 preorder [3,9,20,15,7] inorder [9,3,15,20,7] # 左斜树 preorder [1,2,3] inorder [3,2,1] # 右斜树 preorder [1,2,3] inorder [1,2,3] # 单节点 preorder [1] inorder [1] # 空树 preorder [] inorder []6. 实际应用与变种问题6.1 实际工程应用配置文件解析很多配置文件采用树形结构存储DOM树重建网页解析时可能需要从序列化数据重建DOM数据库索引某些数据库索引的序列化和反序列化6.2 相关变种题目从中序和后序遍历构造二叉树LeetCode 106从前序和后序遍历构造二叉树LeetCode 889 - 这种情况下树不唯一序列化和反序列化二叉树LeetCode 297根据前序和中序构造二叉搜索树7. 性能优化与注意事项7.1 递归深度问题对于极度不平衡的树递归解法可能导致栈溢出。解决方法使用迭代法设置递归深度限制Python可用sys.setrecursionlimit对于已知的大数据量考虑非递归实现7.2 内存使用优化避免在递归过程中不断创建新的数组切片使用索引范围来标识当前处理的子序列对于特别大的树考虑使用生成器或迭代器处理序列7.3 实际编码中的坑数组切片时注意边界条件特别是Python的切片是左闭右开确保前序和中序序列的长度一致处理空子树时要及时返回None在哈希表优化版本中注意inorder_map要提前构建8. 扩展思考与进阶学习8.1 为什么前序后序不能唯一确定二叉树因为无法确定左右子树的划分点。例如 前序[1,2,3] 后序[3,2,1] 可能对应1 1 / \ 2 2 \ / 3 38.2 如何验证重建的二叉树是否正确对重建的树重新进行前序和中序遍历检查是否与输入一致编写树的结构比较函数使用可视化工具绘制二叉树8.3 对于大规模树的处理当树非常大时比如百万节点级别考虑使用非递归实现可以分块处理树的各个部分可能需要使用磁盘存储中间结果我在实际面试中遇到这个问题时通常会先解释清楚原理然后实现基础递归版本接着讨论优化方案最后可能会被要求写迭代版本。这种循序渐进的方式能很好展示问题解决能力。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑