力扣解题-101. 对称二叉树

0 阅读7分钟

力扣解题-101. 对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

示例 1:

image.png

输入:root = [1,2,2,3,4,4,3]

输出:true

示例 2:

image.png

输入:root = [1,2,2,null,3,null,3]

输出:false

提示:

树中节点数目在范围 [1, 1000] 内

-100 <= Node.val <= 100

进阶:你可以运用递归和迭代两种方法解决这个问题吗?

Related Topics

树、深度优先搜索、广度优先搜索、二叉树


第一次解答

解题思路

核心方法:递归法(深度优先搜索 DFS),将“判断整棵树是否对称”拆解为“判断左右子树是否镜像对称”,通过辅助函数逐节点校验镜像位置的节点是否满足“结构相同+值相同”,逻辑清晰且时间/空间复杂度最优。

核心逻辑拆解(通俗版)

判断二叉树轴对称的核心是“镜像对比”——左子树的左节点对应右子树的右节点,左子树的右节点对应右子树的左节点,需同时满足结构对称值对称

  1. 主函数处理根节点
    • 若根节点root == null(空树),直接返回true(空树天然对称);
    • 调用辅助函数isCompare(root.left, root.right),校验左右子树是否镜像对称;
  2. 辅助函数镜像校验
    • 基线条件1(双空节点):left == null && right == null,镜像位置都无节点,返回true
    • 基线条件2(结构不对称):left == null || right == null(仅一个节点为空),返回false
    • 基线条件3(值不对称):left.val != right.val,返回false
    • 递归校验深层镜像节点:
      • isCompare(left.left, right.right):左子树的左节点 ↔ 右子树的右节点;
      • isCompare(left.right, right.left):左子树的右节点 ↔ 右子树的左节点;
    • 合并结果:只有两层镜像校验都通过(aResult && bResult),才返回true
具体步骤(以示例1 root=[1,2,2,3,4,4,3]为例)
递归层级对比节点(left,right)校验结果说明
1(2,2)-值相同,递归校验深层
2(3,3)true双叶子节点,结构+值对称
2(4,4)true双叶子节点,结构+值对称
3(null,null)true镜像位置都为空
最终结果为true,与示例一致。
性能说明
  • 时间复杂度:O(n)(n为节点总数,每个节点仅被对比一次);
  • 空间复杂度:O(h)(h为树的高度,递归调用栈的深度等于树的高度):
    • 最好情况(平衡二叉树):h = log₂n,空间复杂度O(logn);
    • 最坏情况(斜树):h = n,空间复杂度O(n);
  • 优势:
    1. 镜像对比逻辑精准,辅助函数将对称判断拆解为原子问题,易理解;
    2. 短路特性:只要某一层级校验失败,后续递归直接终止,执行效率高;
    3. 天然处理空树、单节点树等边界场景。
    public boolean isSymmetric(TreeNode root) {
        if(root==null){
            return true;
        }
        return isCompare(root.left,root.right);
    }

    public boolean isCompare(TreeNode left, TreeNode right) {
        if(left==null && right==null){
            return true;
        }
        if(left==null && right !=null){
            return false;
        }
        if(left!=null && right==null){
            return false;
        }
        if(left.val != right.val){
            return false;
        }
        boolean aResult=isCompare(left.left,right.right);
        boolean bResult=isCompare(left.right,right.left);
        return aResult && bResult;
    }

示例解答

解题思路

解法1:迭代法(广度优先搜索 BFS / 层序遍历)

核心方法:队列辅助镜像层序对比,利用队列存储镜像位置的节点对,逐层校验每一对节点是否满足“结构+值对称”,属于“自顶向下”的迭代实现,避免递归栈的调用,满足进阶要求。

代码实现
import java.util.LinkedList;
import java.util.Queue;

public boolean isSymmetric(TreeNode root) {
    if (root == null) {
        return true;
    }
    // 队列存储镜像位置的节点对
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root.left);
    queue.offer(root.right);
    
    while (!queue.isEmpty()) {
        // 取出一对镜像节点
        TreeNode left = queue.poll();
        TreeNode right = queue.poll();
        
        // 双空节点,跳过后续校验
        if (left == null && right == null) {
            continue;
        }
        // 结构不对称或值不对称,直接返回false
        if (left == null || right == null || left.val != right.val) {
            return false;
        }
        
        // 按镜像顺序加入下一层节点对
        queue.offer(left.left);
        queue.offer(right.right);
        queue.offer(left.right);
        queue.offer(right.left);
    }
    // 所有镜像节点对比完成,均对称
    return true;
}
核心逻辑说明
  1. 队列初始化:将根节点的左右子节点作为第一对镜像节点入队;
  2. 层序镜像对比
    • 每次取出一对节点,校验逻辑与递归法的辅助函数一致;
    • 按“左左→右右、左右→右左”的镜像顺序入队下一层节点,保证对比顺序正确;
  3. 返回结果:队列遍历完成后,说明所有镜像节点都对称,返回true
性能说明
  • 时间复杂度:O(n)(每个节点仅入队/出队一次);
  • 空间复杂度:O(n)(最坏情况队列存储一层所有镜像节点对,如完全二叉树的最后一层);
  • 优势:非递归实现,避免递归栈溢出风险(如树高度极大时);
  • 劣势:需要额外的队列空间,代码量略多于递归法。
解法2:迭代法(深度优先搜索 DFS / 栈模拟)

核心方法:栈模拟递归过程,用栈存储镜像位置的节点对,按“根→右→左”的镜像顺序入栈,逐节点校验结构和值是否对称,逻辑与递归法等价但无递归栈开销。

代码实现
import java.util.Stack;

public boolean isSymmetric(TreeNode root) {
    if (root == null) {
        return true;
    }
    // 栈存储镜像位置的节点对
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root.left);
    stack.push(root.right);
    
    while (!stack.isEmpty()) {
        // 取出一对镜像节点(栈后进先出,先取right再取left)
        TreeNode right = stack.pop();
        TreeNode left = stack.pop();
        
        // 双空节点,跳过
        if (left == null && right == null) {
            continue;
        }
        // 结构/值不对称
        if (left == null || right == null || left.val != right.val) {
            return false;
        }
        
        // 按镜像顺序入栈下一层节点(保证左左↔右右、左右↔右左的顺序)
        stack.push(left.left);
        stack.push(right.right);
        stack.push(left.right);
        stack.push(right.left);
    }
    return true;
}
核心逻辑说明
  1. 栈初始化:将根节点的左右子节点作为第一对镜像节点入栈;
  2. 栈遍历镜像对比
    • 弹出一对节点(注意栈后进先出,先弹right再弹left);
    • 校验逻辑与递归法一致;
    • 按“左左→右右、左右→右左”的镜像顺序入栈,保证深层节点的对比顺序正确;
  3. 返回结果:栈遍历完成后返回true
性能说明
  • 时间复杂度:O(n)(每个节点仅入栈/出栈一次);
  • 空间复杂度:O(h)(h为树的高度,栈的深度等于树的高度);
  • 优势:非递归实现,可控性更高,避免递归栈溢出;
  • 劣势:代码量多于递归法,需要手动管理栈的入栈/出栈顺序。
解法3:递归代码优化(精简基线条件)

核心方法:在原递归逻辑基础上,精简基线条件的写法,代码更简洁但逻辑等价,可读性更高。

代码实现
public boolean isSymmetric(TreeNode root) {
    return root == null || isCompare(root.left, root.right);
}

private boolean isCompare(TreeNode left, TreeNode right) {
    // 合并结构不对称的基线条件
    if (left == null || right == null) {
        return left == right;
    }
    // 值不对称直接返回false
    if (left.val != right.val) {
        return false;
    }
    // 递归校验镜像节点
    return isCompare(left.left, right.right) && isCompare(left.right, right.left);
}
优势说明
  • 逻辑等价:与原递归解法完全一致,仅代码写法优化;
  • 代码更精简:将“双空、一空一非空”的判断合并为left == right,减少冗余代码;
  • 可读性更高:核心逻辑更突出,新手易理解。

总结

  1. 递归DFS法(第一次解答):O(n)时间+O(h)空间,逻辑清晰、镜像对比精准,是判断对称二叉树的最优解法,工程中优先使用;
  2. 迭代BFS法(层序遍历):O(n)时间+O(n)空间,非递归实现,满足进阶要求,适合避免递归栈的场景;
  3. 迭代DFS法(栈模拟):O(n)时间+O(h)空间,与递归法空间复杂度一致,代码稍复杂;
  4. 递归精简版:代码更简洁,逻辑等价,可读性更高;
  5. 关键技巧:
    • 核心思想:对称二叉树的本质是“左右子树镜像对称”,需对比left.left↔right.rightleft.right↔right.left
    • 基线条件:优先判断“结构对称”(双空/一空一非空),再判断“值对称”;
    • 方法选择:优先选递归法(代码简洁),树高度极大时选迭代法(避免栈溢出)。