【力扣-101.对称二叉树】Python笔记

0 阅读4分钟

对称二叉树:别再傻傻地遍历了,这才是面试官想看的解法!

摘要:判断二叉树是否对称,你还在想着把左右子树遍历出来比对吗?太慢啦!本文带你用最优雅的递归法(双指针思想)解决 LeetCode 101 题。通过拆解“镜像”的本质,配合保姆级代码注释,让你彻底搞懂这道高频面试题!


前言

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

今天我们来聊聊 LeetCode 上的一道经典题目——101. 对称二叉树

这道题看似简单,很多小伙伴第一反应可能是:“把左子树遍历一遍,把右子树遍历一遍,然后反转其中一个数组比对一下不就行了?”

打住!虽然这也能做,但不仅空间复杂度高,而且代码写起来啰嗦。面试官通常想看到的是你对树结构递归逻辑的深刻理解。

今天,咱们就用最优雅的递归法,手把手教你如何让代码像诗一样优美。


核心知识点:什么是“镜像对称”?

在做题之前,我们得先达成一个共识:什么叫对称?

就像我们要照镜子一样,一棵树如果是对称的,意味着它的左子树右子树是互为镜像的。

那么,两个树互为镜像,需要满足什么条件呢?

  1. 根节点的值必须相同。
  2. 树 A 的左子树必须和树 B 的右子树镜像。
  3. 树 A 的右子树必须和树 B 的左子树镜像。

大家发现没有?这本身就是一个递归的定义!

通俗理解
想象两个小人,一个站在左子树,一个站在右子树。

  • 他们俩的值要一样。
  • 左边小人的“左手”(左孩子),要和右边小人的“右手”(右孩子)一样(这是外层)。
  • 左边小人的“右手”(右孩子),要和右边小人的“左手”(左孩子)一样(这是内层)。

解题思路:双树递归(辅助函数法)

既然我们要比较的是“左子树”和“右子树”,那我们的递归函数就不应该只接收一个节点,而是接收两个节点

步骤拆解:

  1. 主函数isSymmetric 负责处理边界情况(比如根节点为空),然后启动递归,传入 root.leftroot.right

  2. 辅助函数check(left, right) 负责具体的比对逻辑。

    • 终止条件 1:如果两个人都走到底了(都为空),说明这一路没问题,返回 True

    • 终止条件 2:如果一个人走到底了,另一个还没(一个空一个不空),那肯定不对称,返回 False

    • 终止条件 3:两个人的值不一样,不对称,返回 False

    • 递归推进:如果上面都没问题,那就继续往里层探测:

      • 检查外侧left.left vs right.right
      • 检查内侧left.right vs right.left
      • 两者都满足才算 True

代码实战: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 isSymmetric(self, root: Optional[TreeNode]) -> bool:
        # 如果根节点为空,按照定义通常认为是对称的
        if not root:
            return True
        
        # 核心入口:我们要检查的是根节点的左孩子和右孩子是否互为镜像
        return self.check(root.left, root.right)

    # 辅助函数:检查两棵树(p 和 q)是否互为镜像
    def check(self, left: Optional[TreeNode], right: Optional[TreeNode]) -> bool:
        # 1. 【递归出口】如果两个节点都为空,说明比对到了尽头,是对称的
        if not left and not right:
            return True
        
        # 2. 【递归出口】如果其中一个为空,另一个不为空,肯定不对称
        if not left or not right:
            return False
        
        # 3. 【递归出口】如果两个节点的值不相等,不对称
        if left.val != right.val:
            return False
        
        # 4. 【核心递归逻辑】
        # 此时 left 和 right 的值是相等的,我们需要继续检查它们的子节点
        # 必须同时满足以下两个条件:
        #   A. 左节点的左孩子 和 右节点的右孩子 对称(检查外侧)
        #   B. 左节点的右孩子 和 右节点的左孩子 对称(检查内侧)
        return self.check(left.left, right.right) and self.check(left.right, right.left)

总结与延伸

这道题的精髓在于打破惯性思维

通常我们写树的递归,函数签名是 func(node),处理当前节点然后递归左右。但这道题我们需要同步处理两个节点,所以函数签名变成了 func(left, right)

知识点复盘:

  • 递归三要素:确定参数(两个节点)、确定终止条件(空值判断、值不等判断)、确定单层逻辑(内外侧比对)。
  • 镜像定义:左对右,右对左。

学会了这个思路,以后遇到类似的“比较两棵树”的题目(比如 LeetCode 100. 相同的树),你也能举一反三,轻松搞定!

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