LeetCode 101. 对称二叉树

LeetCode 101. 对称二叉树

摘要

LeetCode 101 对称二叉树题解,使用栈(迭代法)成对比较镜像节点,判断二叉树是否轴对称,时间复杂度 O(n),空间复杂度 O(n)。

标签

#算法 #LeetCode #二叉树 #栈 #迭代 #题解

目录

  1. 题目描述
  2. 易错点
  3. 思路
  4. 编写代码

1. 题目描述

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

示例 1:

text

ini 复制代码
输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:

text

csharp 复制代码
输入:root = [1,2,2,null,3,null,3]
输出:false

提示:

  • 树中节点数目范围是 [1, 1000]
  • -100 <= Node.val <= 100

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


2. 易错点

  1. 空树视为对称,直接返回 true
  2. 栈中存储的是成对的节点指针,每次弹出两个节点进行比较。
  3. 压栈顺序必须严格按照镜像对称关系,否则比较逻辑会错乱。
  4. 当两个节点都为空时,跳过此次循环,继续比较下一对。
  5. 当其中一个为空或值不相等时,立即返回 false 并释放栈内存。
  6. 遍历结束后释放栈内存,避免内存泄漏。

3. 思路

核心思想

判断二叉树是否对称,本质是比较左子树右子树是否互为镜像。镜像比较的规则是:

  • 左子树的左孩子 对应 右子树的右孩子
  • 左子树的右孩子 对应 右子树的左孩子

栈的原理

本题使用(而非递归)来实现迭代比较。栈的作用类似于一个"待比较节点对"的任务队列(后进先出),每次取出两个节点进行比较,再将它们的子节点按镜像规则成对压栈。

为什么栈可以实现对称判断?

可以将栈理解为存储"比较任务"的容器。与普通二叉树遍历不同,遍历时每次只处理一个节点,而本题每次从栈中弹出两个节点进行比较。这两个节点是当前这一层需要判断是否对称的一对节点。

压栈过程是关键:

text

scss 复制代码
stack[top++] = l->left;   // 左子树的左孩子
stack[top++] = r->right;  // 右子树的右孩子  → 与上一行成对比较
stack[top++] = l->right;  // 左子树的右孩子
stack[top++] = r->left;   // 右子树的左孩子  → 与上一行成对比较

为什么是这种顺序?

  • 栈是后进先出的,意味着后压入的节点会先被弹出比较。

  • 入栈顺序为:l->left, r->right, l->right, r->left

  • 出栈顺序则变为:r->leftl->right 先被弹出(因为最后压入),然后才是 r->rightl->left

  • 但这里的入栈顺序经过精心设计,使得弹出的每一对正好是需要比较的镜像节点:

    • 第一次弹出:r->leftl->right(镜像对应)
    • 第二次弹出:r->rightl->left(镜像对应)

实际上,压栈操作是将"需要比较的两对节点"依次压入栈中。由于每次弹出两个节点,栈的设计保证了它们被正确配对。

与传统遍历的区别:

传统前序/中序/后序遍历每次只压入一个节点,处理的逻辑是"当前节点的子节点"。而本题每次压入四个节点(两对),出栈时按两两配对的方式进行比较,栈顶的两个节点(先弹出的一对)和次顶的两个节点(后弹出的一对)分别代表了左右子树的两个镜像分支。

这种"成对压栈、成对弹出"的模式使得栈能够模拟递归的成对比较过程,同时避免了递归栈可能带来的栈溢出风险。

算法步骤

  1. root 为空,返回 true

  2. 初始化栈,将 root->leftroot->right 压入栈(作为第一对待比较节点)。

  3. 循环执行以下操作,直到栈空:

    • 从栈中弹出两个节点 l(左节点)和 r(右节点)。

    • lr 都为空,则跳过此次循环。

    • 若其中一个为空或值不相等,则返回 false

    • 否则按镜像对称顺序压入子节点:

      • 先压 l->left,再压 r->right(这对会在后面被一起弹出比较)
      • 再压 l->right,再压 r->left(这对也会在后面被一起弹出比较)
  4. 循环正常结束,返回 true


4. 编写代码

c 运行

c

ini 复制代码
bool isSymmetric(struct TreeNode* root) {
    if (root == NULL) return true;
    struct TreeNode** stack = (struct TreeNode**)malloc(10000 * sizeof(struct TreeNode*));
    int top = 0; 
    stack[top++] = root->left;
    stack[top++] = root->right;

    while (top > 0) {
        struct TreeNode* r = stack[--top];
        struct TreeNode* l = stack[--top];
        if (l == NULL && r == NULL) continue;
        if (l == NULL || r == NULL || l->val != r->val) {
            free(stack);
            return false;
        }
        stack[top++] = l->left;
        stack[top++] = r->right;
        stack[top++] = l->right;
        stack[top++] = r->left;
    }

    free(stack);
    return true;
}
相关推荐
6Hzlia2 小时前
【Classic 150 刷题计划】 LeetCode 205. 同构字符串 | C++ 双向绑定与哈希表映射
c++·算法·leetcode
有点。9 小时前
C++03阶段练习(练习题)
数据结构·算法·图论
周末也要写八哥10 小时前
经典算法实例:游戏中弱角色的数量(二)
算法
是Yu欸10 小时前
鸿蒙PC移植:2048 从网页小游戏到 AI 桌面应用
大数据·人工智能·算法·数据挖掘·openharmony·codex
鹿角片ljp10 小时前
KV Cache 解析
java·算法
liliangcsdn11 小时前
IVOL与偏度因子的对比测量分析
算法
threerocks12 小时前
Jev 入门第一课
算法
西柚研究生12345613 小时前
论文分析17:YOLOv11_UAVNet:无人机航拍图像专用目标检测算法
人工智能·python·深度学习·算法·目标检测
hetao173383714 小时前
2026-09-17 hetao1733837 的刷题记录
c++·算法
午彦琳14 小时前
2026.9.17
数据结构·算法·leetcode