二叉树:由前序+中序遍历重建,求后序遍历
**# 二叉树:由前序+中序遍历重建,求后序遍历
题目原型
P1827 USACO3.4 美国血统 American Heritage
给定二叉树的前序遍历和中序遍历,输出后序遍历。节点为唯一大写字母,最多 26 个。
知识铺垫:三种遍历回顾
C
/ \
B G
/ \ /
A D H
/ \
E F
| 遍历 | 顺序 | 该树输出 |
|---|---|---|
| 前序 | 根 → 左 → 右 | C B A D E F G H |
| 中序 | 左 → 根 → 右 | A B E D F C H G |
| 后序 | 左 → 右 → 根 | A E F D B H G C |
核心思想:分治递归
给定:pre = "CBADEFGH" (前序)
in = "ABEDFCHG" (中序)
步骤:
1. 前序首字符为根 → root = 'C'
2. 在中序中找到 'C' 的位置 idx = 5
in: A B E D F [C] H G
← 左子树 → ↑ ←右子树→
(idx个) (len-idx-1个)
3. 切割:
左子树中序 = in[0:idx] → "ABEDF"
左子树前序 = pre[1:1+idx] → "BADEF"
右子树中序 = in[idx+1:] → "HG"
右子树前序 = pre[1+idx:] → "GH"
4. 递归构建左、右子树
5. 后序排列:左后序 + 右后序 + 根
ASCII 递归过程:
pre="CBADEFGH" in="ABEDFCHG"
root='C' idx=5
/ \
左: pre="BADEF" 右: pre="GH"
in="ABEDF" in="HG"
root='B' idx=1 root='G' idx=1
/ \ / \
pre="A" pre="DEF" pre="H" pre=""
in="A" in="EDF" in="H" in=""
root='A' root='D' root='H' return ""
idx=0 idx=1 idx=0
/ \ / \ / \
"" "" pre="E" pre="F" "" ""
in="E" in="F"
idx=0 idx=0
/ \ / \
"" "" "" ""
后序拼接(自底向上):
A → A E→E F→F H→H
A + "" + "" = A
E + F + D = EFD
A + EFD + B = AEFDB
H + "" + G = HG
AEFDB + HG + C = AEFDBHGC ✓
代码模板
def build(in_o, pre_o):
if not pre_o:
return ''
root = pre_o[0] # 前序第一个 = 根
idx = in_o.index(root) # 中序中根的位置
# 切割四段
left_in = in_o[:idx] # 左子树中序
right_in = in_o[idx + 1:] # 右子树中序
left_pre = pre_o[1 : 1 + idx] # 左子树前序
right_pre = pre_o[1 + idx :] # 右子树前序
# 后序 = 左后序 + 右后序 + 根
return (build(left_in, left_pre) +
build(right_in, right_pre) +
root)
边界易错点
1. 输入空格
in_o = input().strip() # 必须 strip,样例第二行末尾有空格,不然只能过70%样例
pre_o = input().strip()
2. 切片范围
左子树节点数 = idx 个
前序切分:
pre[0] → 根(跳过)
pre[1:1+idx] → 左子树前序(紧接根后,取 idx 个)
pre[1+idx:] → 右子树前序(剩下全部)
3. 空子树
if not pre_o: return '' 必须在开头,对应叶子节点的左右空子树。
同类变体
| 已知条件 | 求目标 | 异同 |
|---|---|---|
| 前序 + 中序 | 后序 | 本题,根在前序首 |
| 后序 + 中序 | 前序 | 根在后序尾,其余对称 |
| 前序 + 后序 | 中序 | 不唯一(无法区分单子节点时是左还是右) |
规律:必须有中序才能唯一确定二叉树结构。
时间复杂度
- 每次
index()扫描中序,O(n) - 递归 n 层,每层 O(n) → 总 O(n²)
- 因 n ≤ 26,完全够用。大数据可预处理字符→位置的哈希表优化到 O(n)。
浙公网安备 33010602011771号