226. 翻转二叉树

简单 含交互动画

学完这道你应该能: 说清它为什么用「递归」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

翻转(镜像)整棵二叉树:让每个节点的左右孩子互换,返回根。

原树 = 4 →(2,7), 2→(1,3), 7→(6,9)
翻转后 = 4 →(7,2), 7→(9,6), 2→(3,1)

思路解析

新手常卡在「整棵树那么多节点,到底先动谁、动完会不会影响别处」。如果把它当成一道「全局重排」的题,要同时盯住所有层、所有位置,脑子立刻不够用。

转折:翻转不需要全局视角。到任意节点,只把它的左、右两个孩子互换,再分别递归翻转左右子树,整棵树就自动镜像了。为什么对?因为「镜像」对每个节点的要求都一样——左右对调,递归正好把同一个动作铺满全树。空节点没孩子可换,直接返回。

原树 · 从根 4 出发:原树长这样:4 的左孩子是 2(带 1,3)、右孩子是 7(带 6,9)。递归从根 4 进入,第一件事就是交换它的左右孩子

根 4 · 交换左右孩子:把 4 的左孩子(2)和右孩子(7)对调。注意:交换的是整棵子树,不是只换个数字——原来的右子树(7,6,9)整块挪到左边、左子树(2,1,3)整块挪到右边。

递归进左子树 · 现在是 7:根处理完,递归进它现在的左孩子 7(刚从右边搬过来)。对 7 做同一件事:交换它的两个孩子 6 和 9。

节点 7 · 交换 6 ↔ 9:7 的左孩子(6)和右孩子(9)对调 → 变成 (9, 6)。这俩都是叶子,整块搬就是搬一个节点。换完,继续往 7 的孩子递归。

递归进 9 · 空孩子直接返回:进入 9。它的左右孩子都是,没什么可交换的——空节点是递归的底,直接返回(这就是负例:不是每次递归都真的交换)。它的兄弟 6 同理,也是空孩子直接返回。

左子树翻完 · 回到根 · 递归进右:左子树(7,9,6)全部翻完(标灰)。回到根 4,再递归进它现在的右孩子 2。对 2 做同一件事:交换它的孩子 1 和 3。

节点 2 · 交换 1 ↔ 3:2 的左孩子(1)和右孩子(3)对调 → 变成 (3, 1)。再递归进 3、进 1——都是空孩子的叶子,直接返回,无操作。

完成 · 整棵镜像:每个节点都被交换过一次,整棵树成了原树的镜像:4 →(7,2),7→(9,6),2→(3,1)。和题目给的「翻转后」完全一致。

很多树题的本质都是「对每个节点都做某个简单操作」,用递归自动覆盖全树,你只需想清楚单个节点该干嘛。翻转(换孩子)、给每个节点加值、收集每个节点,全是这个套路的换皮。

参考代码(Python)

Python
1def invertTree(self, root):
2    if not root: return None                          # 空节点直接返回(递归的底)
3    root.left, root.right = root.right, root.left      # 交换左右孩子(一行搞定)
4    self.invertTree(root.left)                        # 递归翻左
5    self.invertTree(root.right)                       # 递归翻右
6    return root

复杂度分析

  • 时间复杂度:O(n) —— 每个节点恰好被访问、交换一次
  • 空间复杂度:O(h) —— 递归栈深度等于树高 h,最坏退化成链表时为 O(n)

套路模板

记住骨架:空则返回、对当前节点做操作、递归左右。只换中间那行「操作」,就能做翻转、加权、剪枝等一大类「对全树统一处理」的题。

Python
1def dfs(node):
2    if not node: return                  # 空则返回(递归的底)
3    操作(node)                           # 对当前节点做事(翻转题=交换左右孩子)
4    dfs(node.left)                       # 递归左
5    dfs(node.right)                      # 递归右

易错点

  • 错误写法:root.left = invert(root.right); root.right = invert(root.left)正确写法:先用元组同时交换 root.left, root.right = root.right, root.left,或先暂存(第一行已把 root.left 改成了翻好的右子树,第二行的 root.left 是新值,整棵树乱套——必须先暂存或用元组赋值一步换好)
  • 错误写法:只交换节点里的值,不动孩子指针正确写法:交换的是 left/right 两个子树指针(镜像要把整棵子树搬过去,只换根的值,子树结构还是原样,根本没翻)
  • 错误写法:忘了空节点的判断正确写法:开头 if not root: return None(递归一定会走到叶子的空孩子,不挡住 None 就会在取 .left 时崩)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →102. 二叉树的层序遍历 ← 返回题库