力扣刷题#29-0101-对称二叉树

力扣刷题#29-0101-对称二叉树

题目

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

输入: root = [1,2,2,3,4,4,3]
        1
       / \
      2   2
     / \ / \
    3  4 4  3
输出: true
输入: root = [1,2,2,null,3,null,3]
        1
       / \
      2   2
       \   \
        3   3
输出: false

我的思路之旅:从"想不通"到"搞懂"

第一反应:绕远的想法

看到这题,我试过"翻转左子树再和右子树比较"——逻辑上没错,但要写两个函数,很麻烦。

真正的盲区:我一直在想"怎么处理一棵子树",但对称是"两棵子树互为镜像"的关系。

判断函数要接收两个节点,交叉比较——左子树的外侧对应右子树的外侧,内侧对应内侧。

镜像的交叉对应

        1
       / \
      2   2
     / \ / \
    3  4 4  3

比较对 1: 左的 left(3) ↔ 右的 right(3)   ← 镜像的外侧
比较对 2: 左的 right(4) ↔ 右的 left(4)   ← 镜像的内侧

生活化类比:左右手是否互为镜像?左手拇指对右手拇指,但位置是交叉的——照镜子就明白了。


解法一:递归版(我的代码)

class Solution {
public:
    bool isMirror(TreeNode* n1, TreeNode* n2) {
        if (!n1 || !n2)
            return n1 == n2; // 如果至少一个为空,判断是否全空
        if (n1->val != n2->val)
            return false;    // 如果值不同,返回false
        return isMirror(n1->right, n2->left) && isMirror(n1->left, n2->right);
    }
    bool isSymmetric(TreeNode* root) {
        return isMirror(root->left, root->right);
    }
};

递归逻辑三层

判断 动作
① 出口 至少一个为空 return n1 == n2(都空才对)
② 值 值不等 return false
③ 递归 值相等 交叉比较:(右, 左)(左, 右)

我困惑的点:isMirror 怎么才能返回 true?

true 的种子在最底层:两个空指针相遇时判定为镜像。

isMirror(4, 4)
  → 值相等,继续
  → isMirror(null, null)  ← 两个都空
       → return (null == null) = TRUE ✅
  → && isMirror(null, null) = TRUE ✅
  → 返回 true

true 从最底层一路 && 传回顶层。只要整棵树对称,每一层都成立。

我踩的坑:函数不能套函数

第一版我把 isMirror 定义在 isSymmetric 里面——标准 C++ 不允许函数内定义函数,编译报错。要写成类的私有成员函数。


解法二:迭代版(我的代码)

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        queue<TreeNode*> qu;
        qu.push(root->left);
        qu.push(root->right);

        while (!qu.empty()) {
            TreeNode* n1 = qu.front(); qu.pop();
            TreeNode* n2 = qu.front(); qu.pop();

            // 判断是否为镜像,先处理不是的情况
            if (!n1 && !n2) continue;              // 都空,处理队列中其他的
            if (!n1 || !n2) return false;          // 一个空,返回false
            if (n1->val != n2->val) return false;  // 值不等,返回false

            // 走到这里说明两个节点为镜像,入队交叉对
            qu.push(n1->left); qu.push(n2->right);
            qu.push(n1->right); qu.push(n2->left);
        }
        // 走完队列没有返回false,说明全部为镜像
        return true;
    }
};

思路:递归的调用栈换成队列

迭代版把"要比较的节点对"放进队列,一次取一对出来比。递归的 isMirror(n1, n2) 变成队列里的 (n1, n2) 对。

我困惑的点:if 判断条件怎么写?

写 if 分支 = 穷举所有情况 + 安全排序 + 失败早退。

第一步:穷举。取出一对 (n1, n2),只有 4 种情况:

情况 n1 n2 结论
这对匹配 ✅ continue
非空 不镜像 ❌ false
非空 不镜像 ❌ false
非空 非空 看值是否相等

第二步:安全排序。判空永远在判值前面——空指针不能访问 ->val

第三步:失败早退。所有失败情况提前 return false


我困惑的点:什么时候 return false / return true?

false 可以提前走,true 必须最后走。

位置 返回什么 原因
循环内发现违规 return false 错误是决定性的,发现即定案
循环内全部通过 不能 return true 后面可能还有不匹配的
循环彻底走完 return true 所有节点对都查过且通过

通用心法

循环 {
    if (不满足) return false;   // 违反就早退
}
return true;                     // 全部检查完才返回 true

"对称"是全称判断——必须所有节点对都通过才能下结论。中途的"暂时通过"随时可能被后面的推翻。


递归 vs 迭代

对比 递归 迭代
数据结构 函数调用栈 队列
对应关系 isMirror(n1, n2) 队列存 (n1, n2)
交叉入队 isMirror(右, 左) && isMirror(左, 右) qu.push(右); qu.push(左) 交叉
空对处理 出口 n1==n2 continue
失败 逐层返回 false 立即 return false

复杂度分析

维度 递归 迭代
时间复杂度 O(n) O(n)
空间复杂度 O(h) 递归栈 O(n) 队列

关键点总结

关键点 说明
核心思路 对称 = 两棵子树互为镜像,交叉比较
交叉对 (左外, 右外)(左内, 右内)
判断心法 穷举 + 先判空后判值 + 失败早退
true/false 时机 false 提前走,true 最后走
递归换迭代 DFS 用栈模拟,BFS 用队列

本文档由 AI 辅助生成,作者提供问题,思路和代码,AI仅负责文本修饰,综合获得以上内容。

posted @ 2026-08-08 20:14  STA_running  阅读(2)  评论(0)    收藏  举报