翻转二叉树:从入门到“入土”
摘要:据说会这道题就能去 Google 上班?今天咱们来盘一盘 LeetCode 226 题“翻转二叉树”。别被它吓到,其实它就是让二叉树“照镜子”。本文将用最通俗的语言带你理解递归的精髓,代码注释拉满,助你轻松拿捏这道经典面试题!
前言
哈喽大家好,我是爱摸鱼的打工仔。
今天我们要聊的这道题,江湖传说非常广——据说 Homebrew 的作者 Max Howell 去 Google 面试,因为没写出来这道题被拒了。
这道题就是 LeetCode 226. 翻转二叉树。
别慌,虽然它难倒过大神,但只要掌握了递归的思维,你会发现它简单得可爱。今天咱们就彻底把它拿下!
核心知识点:什么是翻转二叉树?
在写代码之前,咱们先得把“翻转”这个动作理解透彻。
想象一下,你站在一棵二叉树面前,面前有一面镜子。
- 原本在左边的节点,现在跑到了右边。
- 原本在右边的节点,现在跑到了左边。
翻转二叉树,本质上就是交换每一个节点的左右子树。
核心逻辑:
对于树中的每一个节点,我们都要执行一次操作:swap(node.left, node.right)。
听起来很简单对吧?但怎么遍历整棵树并执行这个操作呢?这就轮到我们的老朋友——递归登场了。
解题思路:递归的“乾坤大挪移”
递归解题,咱们只需要关注三件事:
- 终止条件:什么时候停下来?
- 拆解问题:大事化小。
- 当前层逻辑:我要做什么?
具体步骤如下:
-
终止条件:如果当前节点是空的(
null),那还翻个啥?直接返回null。 -
拆解问题:
- 想要翻转整棵树,我是不是得先把左子树翻转好?
- 是不是也得先把右子树翻转好?
- 这就是递归调用:
invertTree(root.left)和invertTree(root.right)。
-
当前层逻辑:
- 等左右子树都翻好了,我只需要把它们互换位置(
root.left指向翻好的右子树,root.right指向翻好的左子树)。 - 最后把当前的
root返回上去,交给上一层处理。
- 等左右子树都翻好了,我只需要把它们互换位置(
代码实战:Python 递归法
来,直接上代码!为了让大家看得更清楚,我把每一行都加上了“人话”注释。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
# 1. 递归终止条件
# 如果节点为空,说明到底了,或者是空树,直接返回 None
if not root:
return None
# 2. 递归拆解(后序遍历的思想)
# 先把左子树翻好,拿到翻转后的新左子树(其实是原来的右子树)
left = self.invertTree(root.left)
# 再把右子树翻好,拿到翻转后的新右子树(其实是原来的左子树)
right = self.invertTree(root.right)
# 3. 核心操作:交换!
# 把翻好的右子树挂到左边
root.left = right
# 把翻好的左子树挂到右边
root.right = left
# 4. 返回当前节点
# 告诉上一层:“嘿,以我为根节点的这棵小树已经翻好了,拿去用吧!”
return root
代码解析:
- 这里其实用到了后序遍历(左右中)的逻辑:先处理孩子,再处理自己。
- 当然,你也可以用前序遍历(中左右):先交换自己的左右孩子,再递归去处理孩子。效果是一样的,但后序遍历更符合“自底向上”的直觉。
进阶思考:能不能用迭代法?
既然递归能解决,那能不能用迭代(循环)来解决呢?
当然可以!既然递归是利用系统栈,那我们手动维护一个**队列(Queue)或者栈(Stack)**不就行了?
思路如下:
- 把根节点放进队列。
- 只要队列不空,就弹出一个节点。
- 交换这个节点的左右孩子。
- 如果孩子不为空,把孩子塞进队列,留着下一轮处理。
这其实就是 层序遍历(BFS) 的变种。虽然代码稍微长一点,但避免了递归可能导致的栈溢出风险(虽然这道题一般不会溢出)。
总结
翻转二叉树这道题,其实是考察我们对树形结构和递归思维的理解。
- 关键点:不要试图在脑子里把整棵树翻转的过程一步步跑完,那样会晕的!
- 心法:相信你的递归函数。你只要定义好:“给我一个根节点,我能把以它为根的树翻转好”。然后利用这个定义,去处理左右子树即可。
好了,今天的“摸鱼”笔记就记到这里。这道题虽然简单,但它是理解更复杂树形 DP 问题的基石,建议大家多敲几遍,形成肌肉记忆!
我是爱摸鱼的打工仔,咱们下道题见!