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;
}
相关推荐
.道阻且长.5 小时前
2.LeetCode算法习题讲解--双指针--复写零
算法·leetcode·职场和发展
To_OC7 小时前
LC 438 找到所有字母异位词:暴力超时后,我靠滑动窗口一招搞定
javascript·算法·leetcode
Forever Nore10 小时前
学完C语言力扣第一题做不来正常吗
数据结构·算法
hansang_IR10 小时前
【题解】LC:倍增 / 区间并查集(Range Parallel Unionfind)
c++·算法·并查集
Tisfy12 小时前
LeetCode 3731.找出缺失的元素:哈希 / 排序
算法·leetcode·哈希算法·排序·哈希表
lucas_AI12 小时前
Q-CueGraph:你的多模态大模型会 zoom,但真的知道该看哪儿吗?
人工智能·算法
kaixin_啊啊12 小时前
test_机器学习算法学习
学习·算法·机器学习
liulilittle12 小时前
MOE路由:路由(logits: top-k/8)
c++·人工智能·算法·机器学习·llm
旖旎夜光12 小时前
LeetCode 11:盛最多水的容器(双指针问题) —— 题解
数据结构·c++·算法·leetcode·双指针