101. 对称二叉树 (Easy)
专题归类: 05-二叉树 LeetCode 链接: https://leetcode.cn/problems/symmetric-tree/
在线做题: 写 Python 代码并运行 · Java 跳转 LeetCode
题目描述
给你一个二叉树的根节点 root,检查它是否轴对称。
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
提示:
- 树中节点数目在范围
[1, 1000]内 -100 <= Node.val <= 100
进阶: 你可以用递归和迭代两种方法解决吗?
题目详细分析
- 数据范围含义: 节点数最多 1000,值范围 [-100, 100],递归深度最多 1000,安全。
- 输入输出特征: 输入是整棵树的根节点,输出是布尔值 True/False。
- 边界条件: 树只有根节点时返回 True(单个节点对称)。空树?题目提示节点数 >= 1。
- 核心约束: 轴对称不是左右子树完全相同,而是镜像相同。比较的是:
左.left == 右.right且左.right == 右.left。 - 隐藏条件: 比较的是结构对称和值相等,不是引用相等。
小白版直白理解
就像检查一个人的脸是否左右对称——你不需要把左边脸复制到右边,而是要看左边的右半边是否等于右边的左半边。同理,检查二叉树对称:左子树的左孩子要和右子树的右孩子一样,左子树的右孩子要和右子树的左孩子一样。
解题思路
思路一:递归双指针法(推荐)
核心思想: 同时用两个指针 p 和 q,p 从根节点的左子树出发,q 从根节点的右子树出发。p 往左走时 q 往右走(镜像对称),p 往右走时 q 往左走。
为什么用这种特殊的遍历顺序? 普通的单指针遍历无法检查镜像对称——因为对称是需要「交叉对比」的。双指针法让两个指针按镜像轨迹移动,完美匹配对称的定义。
def isSymmetric(root):
def check(p, q):
# 两个都为空:对称
if not p and not q:
return True
# 一个为空一个不为空:不对称
if not p or not q:
return False
# 值不相等:不对称
if p.val != q.val:
return False
# 递归检查:p 的左 vs q 的右,p 的右 vs q 的左
return check(p.left, q.right) and check(p.right, q.left)
return check(root.left, root.right)思路二:迭代法(队列)
用队列成对地放入需要比较的节点。每次取出两个节点比较,然后按照镜像顺序放入它们的子节点。
为什么用队列? 队列可以保持成对比较的顺序,不需要递归调用栈,对树深度很大的情况更安全。
from collections import deque
def isSymmetric(root):
q = deque([root.left, root.right])
while q:
p1 = q.popleft()
p2 = q.popleft()
# 两个都为空:继续检查下一对
if not p1 and not p2:
continue
# 一个为空或值不等:不对称
if not p1 or not p2 or p1.val != p2.val:
return False
# 成对入队(镜像顺序)
q.extend([p1.left, p2.right])
q.extend([p1.right, p2.left])
return True易错点
- 比较方向搞反: 不是
check(p.left, q.left),而是check(p.left, q.right)——因为是对称比较,左的左 vs 右的右。 - 空节点判断顺序: 先判断「两者都空→True」,再判断「一个空→False」,顺序不能乱。如果先判断一个空会把两个都空的情况误判为 False。
- 迭代法 continue 而非 return: 当两个都为空时要用
continue跳过这对,而不是return True,因为还有别的节点等待检查。 - 值比较用 !=: 严格来说,对称要求值相等,所以
p.val != q.val时返回 False。
框架提炼
双指针镜像比较模板:
当需要比较两个树是否对称/相同/相似时,使用双指针(或多指针)同时遍历两棵树:
def compare(p, q):
if not p and not q:
return True # 都空 → 一致
if not p or not q:
return False # 一个空 → 不一致
if p.val != q.val:
return False # 值不同 → 不一致
# 根据具体问题定义如何递归比较
return compare(p.left, q.right) and compare(p.right, q.left)这种模式可以扩展到「相同的树」(左右方向对应)、「子树判断」等问题。
关联题目
- 226-翻转二叉树 — 翻转和对称是互逆操作:翻转后和自己相同则对称;对称树的左子树翻转后等于右子树。
- 100-相同的树 — 双指针比较模板的简化版:p.left vs q.left, p.right vs q.right(相同方向比较)。
- 104-二叉树的最大深度 — 同为二叉树递归基础,但本题的比较涉及两棵树之间的交叉比较。