华为 OD 机试:二叉树重构与节点值计算
在华为 OD 机试的算法环节,二叉树相关的题目出现频率较高。这类问题通常考察两个核心能力:一是根据遍历序列还原树结构,二是基于树的结构进行特定的数值变换。今天我们就结合一道典型题目,聊聊如何用 Python 高效解决。
题目背景
我们需要处理一个二叉树,输入包含中序遍历和前序遍历的整数序列。目标是根据这两组数据重建原始二叉树,并生成一个新的二叉树。新树的每个节点值需要满足特定规则:即该节点的值等于原树中对应位置左子树所有节点值与右子树所有节点值的总和。
这里有个细节需要注意,输入格式通常是两行整数,分别代表中序和前序遍历,以空格分隔。虽然有些测试用例可能格式略有不同,但标准解法应能兼容常见的输入流。
解题思路
1. 重建二叉树
利用前序遍历确定根节点,再在中序遍历中找到根节点的位置,从而划分出左子树和右子树的范围。这是一个经典的递归过程。
- 前序遍历:第一个元素一定是当前子树的根。
- 中序遍历:根节点左侧是左子树,右侧是右子树。
通过记录索引偏移量,我们可以避免每次切片列表带来的额外开销,提升效率。
2. 计算子树和并更新节点
重建完成后,我们需要对树进行一次后序遍历(左右根)。为什么是后序?因为要计算某个节点的左右子树之和,必须先知道子树的结果。
对于每个节点:
- 递归计算左子树的总和。
- 递归计算右子树的总和。
- 将当前节点的值更新为
left_sum + right_sum。
注意边界情况:如果某侧子树为空,其贡献值为 0。
代码实现
下面是一个完整的 Python 实现方案。为了保持代码清晰,我们将树节点定义、构建逻辑和转换逻辑分开编写。
class TreeNode:
def __init__(self, val=0):
self.val = val
self.left = None
self.right = None
def build_tree(preorder, inorder):
"""
根据前序和中序遍历序列重建二叉树
"""
if not preorder or not inorder:
return None
# 前序的第一个元素是根
root_val = preorder[0]
root = TreeNode(root_val)
# 在中序中找到根的位置
idx = inorder.index(root_val)
# 分割左右子树序列
root.left = build_tree(preorder[:idx+], inorder[:idx])
root.right = build_tree(preorder[idx+:], inorder[idx+:])
root
():
node:
left_sum = transform_and_sum(node.left)
right_sum = transform_and_sum(node.right)
node.val = left_sum + right_sum
node.val
():
:
line1 = ().strip()
line2 = ().strip()
line1 line2:
inorder = ((, line1.split()))
preorder = ((, line2.split()))
root = build_tree(preorder, inorder)
total = transform_and_sum(root)
(root.val)
Exception e:
__name__ == :
solve()

