Vvvrf / DSA.log← 返回全部笔记
LEETCODE 101Easy

对称二叉树

对称不是一棵树的性质,而是两棵子树互为镜像的性质,问题从一元变成了二元。

问题拆解

判断一棵树是否轴对称,容易卡在「对称」到底该怎么递归上。如果只盯着单个节点,会发现根本无从下手——对称描述的是根节点左右两半之间的关系,而不是某一个节点自己的属性。

所以要把问题改写成一个二元判断:左子树和右子树是否互为镜像。一旦这样定义,递归的结构就清楚了。

两棵树互为镜像的条件是:根值相等,且「甲的左」镜像「乙的右」、「甲的右」镜像「乙的左」。

递归比较镜像

def isSymmetric(root):
    def mirror(a, b):
        if not a and not b:
            return True
        if not a or not b:
            return False
        return (a.val == b.val
                and mirror(a.left, b.right)
                and mirror(a.right, b.left))

    return mirror(root.left, root.right) if root else True

注意递归调用里的交叉方式:a.leftb.righta.rightb.left。正是这个交叉,把「镜像」的语义落到了代码上。两个都为空说明对称到底了,只有一个为空则结构不对称。

迭代版思路

也可以用一个队列,每次成对取出两个应当镜像的节点做比较,再把它们的孩子按 (a.left, b.right)(a.right, b.left) 成对入队。逻辑和递归完全一致,只是把调用栈换成了显式队列。

复杂度

指标 复杂度 原因
时间 O(n) 每个节点最多被比较一次
空间 O(h) 递归栈深度等于树高

可以迁移的模式

  • 当「一棵树的性质」难以直接递归时,试着把它翻译成「两棵子树之间的关系」;
  • 涉及镜像、对折、回文的问题,往往要让两个指针以相反方向同步推进;
  • 二元递归的终止条件要覆盖「都空」和「只有一个空」两种情况。

把单参数递归升级成双参数,是处理「对比类」树问题的常用一招。