【力扣-226.翻转二叉树】Python笔记

0 阅读4分钟

翻转二叉树:从入门到“入土”

摘要:据说会这道题就能去 Google 上班?今天咱们来盘一盘 LeetCode 226 题“翻转二叉树”。别被它吓到,其实它就是让二叉树“照镜子”。本文将用最通俗的语言带你理解递归的精髓,代码注释拉满,助你轻松拿捏这道经典面试题!


前言

哈喽大家好,我是爱摸鱼的打工仔

今天我们要聊的这道题,江湖传说非常广——据说 Homebrew 的作者 Max Howell 去 Google 面试,因为没写出来这道题被拒了。

这道题就是 LeetCode 226. 翻转二叉树

别慌,虽然它难倒过大神,但只要掌握了递归的思维,你会发现它简单得可爱。今天咱们就彻底把它拿下!


核心知识点:什么是翻转二叉树?

在写代码之前,咱们先得把“翻转”这个动作理解透彻。

想象一下,你站在一棵二叉树面前,面前有一面镜子。

  • 原本在左边的节点,现在跑到了右边。
  • 原本在右边的节点,现在跑到了左边。

翻转二叉树,本质上就是交换每一个节点的左右子树

核心逻辑
对于树中的每一个节点,我们都要执行一次操作:swap(node.left, node.right)

听起来很简单对吧?但怎么遍历整棵树并执行这个操作呢?这就轮到我们的老朋友——递归登场了。


解题思路:递归的“乾坤大挪移”

递归解题,咱们只需要关注三件事:

  1. 终止条件:什么时候停下来?
  2. 拆解问题:大事化小。
  3. 当前层逻辑:我要做什么?

具体步骤如下:

  1. 终止条件:如果当前节点是空的(null),那还翻个啥?直接返回 null

  2. 拆解问题

    • 想要翻转整棵树,我是不是得先把左子树翻转好?
    • 是不是也得先把右子树翻转好?
    • 这就是递归调用:invertTree(root.left)invertTree(root.right)
  3. 当前层逻辑

    • 等左右子树都翻好了,我只需要把它们互换位置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)**不就行了?

思路如下:

  1. 把根节点放进队列。
  2. 只要队列不空,就弹出一个节点。
  3. 交换这个节点的左右孩子。
  4. 如果孩子不为空,把孩子塞进队列,留着下一轮处理。

这其实就是 层序遍历(BFS) 的变种。虽然代码稍微长一点,但避免了递归可能导致的栈溢出风险(虽然这道题一般不会溢出)。


总结

翻转二叉树这道题,其实是考察我们对树形结构递归思维的理解。

  • 关键点:不要试图在脑子里把整棵树翻转的过程一步步跑完,那样会晕的!
  • 心法:相信你的递归函数。你只要定义好:“给我一个根节点,我能把以它为根的树翻转好”。然后利用这个定义,去处理左右子树即可。

好了,今天的“摸鱼”笔记就记到这里。这道题虽然简单,但它是理解更复杂树形 DP 问题的基石,建议大家多敲几遍,形成肌肉记忆!

我是爱摸鱼的打工仔,咱们下道题见!