跳到主要内容

226. 翻转二叉树

题目描述​

给你一棵二叉树的根节点 root,翻转这棵二叉树,并返回其根节点。

翻转:交换每个节点的左右子树。

示例​

示例 1:

输入: root = [4,2,7,1,3,6,9]
输出: [4,7,2,9,6,3,1]

4 4
/ \ / \
2 7 -> 7 2
/ \ / \ / \ / \
1 3 6 9 9 6 3 1

示例 2:

输入: root = [2,1,3]
输出: [2,3,1]

解题思路​

第一步:理解问题本质​

翻转二叉树 = 交换每个节点的左右子节点。

这是一个递归结构的问题:整棵树的翻转 = 左子树翻转 + 右子树翻转 + 交换左右子树。

第二步:暴力解法 - 复制新树​

遍历原树,创建新树,左右子树交换位置。

def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
# 空节点没有左右子树可换,直接返回
if not root:
return None
# 复制一份当前节点,原树保持不动
new_root = TreeNode(root.val)
# 左孩子接「翻转后的右子树」、右孩子接「翻转后的左子树」,这就是翻转
new_root.left = self.invertTree(root.right)
new_root.right = self.invertTree(root.left)
return new_root

为什么不够好:需要创建新节点,空间复杂度 O(n)。

第三步:优化解法 - 原地递归​

直接修改原树的指针,无需创建新节点。

def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
# 递归出口:空节点无处可翻,原样返回
if not root:
return None
# 先递归翻转
# 两个结果必须先存下来:一旦改写 root.left,就再也找不到原来的左子树
left = self.invertTree(root.left)
right = self.invertTree(root.right)
# 再交换
root.left = right
root.right = left
# 当前节点已翻转完,返回给父节点接链
return root

第四步:最优解法 - 递归或迭代​

递归最简洁,迭代(BFS)可以避免栈溢出。


完整代码实现​

算法可视化 · 逐帧回放这道题的代码57 帧 · 录制输入 [4,2,7,1,3,6,9]
from typing import Optional

class Solution:
"""
翻转二叉树 - 递归法

核心思路:
递归地翻转左右子树,然后交换它们。

时间复杂度:O(n)
空间复杂度:O(h) - h 为树高度
"""

def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return None

# 递归翻转左右子树
left = self.invertTree(root.left)
right = self.invertTree(root.right)

# 交换左右子树
root.left = right
root.right = left

return root

示例推演​

以 [4,2,7,1,3,6,9] 为例:

     4
/ \
2 7
/ \ / \
1 3 6 9

递归过程:

  1. invertTree(4)
    • invertTree(2)
      • invertTree(1) -> 返回 1
      • invertTree(3) -> 返回 3
      • 交换:2 的左=3,右=1
      • 返回 2
    • invertTree(7)
      • invertTree(6) -> 返回 6
      • invertTree(9) -> 返回 9
      • 交换:7 的左=9,右=6
      • 返回 7
    • 交换:4 的左=7,右=2
    • 返回 4

结果:

     4
/ \
7 2
/ \ / \
9 6 3 1

复杂度分析​

解法时间复杂度空间复杂度说明
复制新树O(n)O(n)需要额外空间
原地递归O(n)O(h)h 为树高度
BFS 迭代O(n)O(w)w 为树的最大宽度

易错点总结​

1. 忘记返回 root​

错误:

# 子树确实已经原地翻好,但本函数返回 None,父节点接不到它
self.invertTree(root.left)
self.invertTree(root.right)
# 没有 return root

正确:

# 翻转虽然是原地改指针,但调用方要靠返回值接住这棵子树
return root # 必须返回根节点

2. 交换顺序错误​

先交换再递归也可以,但要保持一致:

# 方案一:先递归,后交换
# 拿到的是两棵已经翻转好的子树,最后对调它们的位置
left = self.invertTree(root.left)
right = self.invertTree(root.right)
root.left, root.right = right, left

# 方案二:先交换,后递归
# 交换后 root.left 已经是原右子树,对它递归同样能翻转
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)

3. 空节点处理​

# 空节点上取 .left / .right 会报错,先挡住;返回 None 而不是 root
if not root:
return None # 不是 return root

扩展思考​

1. 翻转 N 叉树​

559. N 叉树的最大深度 类似思路,交换 children 列表。

2. 相关题目​


相关题目​

自测​

加载评论中...