226. 翻转二叉树(Invert Binary Tree)
难度:简单 | 主题:二叉树、递归、DFS
题目
给你一棵二叉树的根节点 root,翻转这棵二叉树,并返回其根节点。
示例
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
翻转前:
4
/ \
2 7
/ \ / \
1 3 6 9
翻转后:
4
/ \
7 2
/ \ / \
9 6 3 1
思路
先讲个故事:照镜子
你站在镜子前举起左手,镜子里的人举起的是右手。翻转二叉树就是给每一棵子树照镜子——交换每个节点的左右孩子。
引导式推导:递归三行
核心操作:对每个节点,交换左右孩子。
递归三步:
-
终止:空节点返回 None
-
递归:先翻转左子树,再翻转右子树(后序),或者先交换再递归(前序)
-
当前层:交换左右孩子
graph TD subgraph 翻转过程 A["4<br/>/ \\<br/>2 7<br/>/ \\ / \\<br/>1 3 6 9"] B["4<br/>/ \\<br/>7 2<br/>/ \\ / \\<br/>6 9 1 3"] C["4<br/>/ \\<br/>7 2<br/>/ \\ / \\<br/>9 6 3 1"] end A -->|"翻转左右子树"| B B -->|"继续翻转子树"| C style C fill:#ffd700
前序 vs 后序:
-
后序:先递归翻转子树,再交换当前节点。更符合直觉:“先把下面的都翻好,我再换”
-
前序:先交换当前节点,再递归翻转子树。也行,但理解起来绕一点
建议用后序,逻辑更清晰。
| 解法 | 时间 | 空间 | 推荐度 |
|---|---|---|---|
| 递归(推荐) | O(n) | O(h) | ⭐⭐⭐⭐⭐ |
| 迭代(栈) | O(n) | O(h) | ⭐⭐⭐ |
代码
# 递归(推荐,推荐写法)
def invertTree(self, root): # 主函数:翻转二叉树
if not root: # 终止:空节点不用翻
return None
# 后序:先翻转左右子树,再交换
left = self.invertTree(root.left)
right = self.invertTree(root.right)
root.left = right # 交换:左接右
root.right = left # 右接左
return root # 返回翻转后的根
# 迭代:用栈模拟 DFS
from collections import deque
def invertTree(self, root): # 主函数:迭代版翻转
if not root:
return None
stack = deque([root])
while stack:
node = stack.pop()
# 交换当前节点的左右孩子
node.left, node.right = node.right, node.left
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return root
复杂度
| 指标 | 值 | 解释 |
|---|---|---|
| 时间 | O(n) | 每个节点访问一次,交换一次 |
| 空间 | O(h) | 递归栈/迭代栈深度,最坏 O(n),平衡树 O(log n) |
关键点
-
递归终止条件不能忘:空节点返回 None
-
交换左右孩子可以在递归前(前序)或递归后(后序),推荐后序
-
不能写成
root.left = self.invertTree(root.right)同时直接递归,会重复翻转
实战考量
频率分析
出现在:经典开场题。这道题常用来考察递归三要素(终止条件、递归调用、当前层操作)。写对了说明你有递归思维。
延伸思考
Q:递归改成迭代怎么写?
A:用栈模拟 DFS 或队列做 BFS。核心逻辑不变——遇到节点就交换左右孩子。
Q:交换左右孩子时,是先递归还是先交换?
A:都可以,但推荐先递归翻转子树再交换(后序)。逻辑更自然:先把下面翻好,我再来换。
Q:如果只翻转奇数层的节点呢?
A:加一个 depth 参数,奇数层交换,偶数层不动。
Q:这题和对称二叉树有什么区别?
A:翻转是”操作”(修改树结构),对称是”判断”(只比较不修改)。翻转是把树变成自己的镜像,对称是判断两棵树是否互为镜像。
易错点
-
不要写成
root.left = self.invertTree(root.right)且在同一层用root.right = self.invertTree(root.left)——此时 root.left 已经被改了 -
用
root.left, root.right = root.right, root.left并行赋值最安全 -
递归终止条件别漏
生活类比
翻转二叉树 → 照镜子 → 递归交换
翻转一棵树,就是让每个节点都照镜子。
后序版本的口诀:先把左右孩子送进镜子间(递归翻转),然后让它们站到对方的位置上(交换)。
就像公司换座位:先让左右两个团队各自内部重新排好座,再让两个团队的经理互换位置。
相关题目
| 题目 | 关系 |
|---|---|
| 101对称二叉树 | 判断两棵树是否镜像(只读,不改) |
| 104二叉树的最大深度 | 同款递归结构 |
→ 返回题单:LeetCode学习路线图 > 五、二叉树
速记卡(面试闪卡)
Q1:一句话讲清「226. 翻转二叉树(Invert Binary Tree)」到底是什么?
A:把二叉树每个节点的左右孩子互换,得到它自己的镜像。
Q2:题目怎么理解? —— 怎么理解?
A:照镜子:你举左手镜中人举右手,翻转就是给每个节点照镜子、交换它的左右孩子。这是经典的面试题翻转二叉树(Invert Binary Tree,即求树的镜像 mirror)。
Q3:递归三步怎么记? —— 怎么理解?
A:像公司换座位:先让左右两个团队各自内部重排好(递归翻子树),再让两个经理互换位置(交换)。终止是遇到空节点返回 None。这是后序递归(post-order recursion)。
Q4:前序还是后序? —— 怎么理解?
A:都能跑,但建议”先把下面翻好再换”更顺:先递归翻左右子树,再交换当前节点。前序(先换再递归)也行但绕。这是前序 vs 后序(pre-order vs post-order)的选择。
Q5:复杂度和实战怎么理解? —— 怎么理解?
A:经典开场题,写对说明你有递归思维。时间 O(n) 每节点访问一次,空间 O(h)(递归栈深,h 是树高)。迭代用栈模拟 DFS 也行。
Q6:核心速记主线有哪些?
-
题目:交换每个节点的左右子树,得到镜像
-
核心:递归终止(空) → 翻子树 → 交换
-
推荐:后序(先翻后换)逻辑最清晰
-
实战:递归三要素开场题,O(n) 时间 O(h) 空间
口诀
A:翻转二叉树,
照镜左右换;
先翻子节点,
再换父不慌。