leetcode算法(101.对称二叉树)

层次遍历

cpp 复制代码
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        // 如果根节点为空,空树被认为是镜像对称的
        if (!root) return true;
        
        // 创建一个队列用于层序遍历,存储待处理的树节点
        queue<TreeNode*> que;
        // 将根节点加入队列,开始层序遍历
        que.push(root);
        
        // 当队列不为空时,继续处理(表示还有节点未遍历)
        while (!que.empty()) {
            // 记录当前层的节点数量(重要:需要在循环前固定大小)
            int size = que.size();
            // 创建一个数组用于存储当前层所有节点的值(包括空节点)
            vector<int> levelValues;
            
            // 遍历当前层的所有节点
            // 注意:使用固定size,因为循环中会向队列添加子节点,que.size()会变化
            for (int i = 0; i < size; i++) {
                // 从队列头部取出节点
                TreeNode* node = que.front();
                que.pop();  // 弹出已处理的节点
                
                // 如果当前节点不为空
                if (node) {
                    // 将当前节点的值加入当前层的数组
                    levelValues.push_back(node->val);
                    // 将左子节点加入队列(无论是否为空,下一层都要处理)
                    que.push(node->left);
                    // 将右子节点加入队列(无论是否为空,下一层都要处理)
                    que.push(node->right);
                } else {
                    // 当前节点为空,使用特殊值INT_MIN标记空节点
                    // 这是为了区分不同节点的值和空节点
                    levelValues.push_back(INT_MIN);
                }
            }
            
            // 检查当前层的节点值数组是否对称
            // 使用双指针从两端向中间比较
            int left = 0, right = levelValues.size() - 1;
            while (left < right) {
                // 如果两端的值不相等,说明不是镜像对称
                if (levelValues[left] != levelValues[right]) {
                    return false;
                }
                // 移动指针继续比较下一对
                left++;
                right--;
            }
            // 如果所有对称位置的节点值都相等,继续检查下一层
        }
        
        // 所有层都检查完毕且都对称,返回true
        return true;
    }
};

关键点详解:

  1. 空节点处理

    • 使用INT_MIN标记空节点,确保能区分节点值为INT_MIN的情况

    • 即使是空节点也要加入队列,确保层次结构正确

  2. 对称检查逻辑

    • 将每一层的节点值收集到数组中

    • 使用双指针检查数组是否回文对称

    • 每层独立检查,只要有一层不对称就返回false

  3. 算法步骤

    • 初始化队列,加入根节点

    • 对于每一层:

      • 获取当前层的所有节点值(包括空节点标记)

      • 检查当前层是否对称

      • 将下一层的节点加入队列

    • 所有层都对称则返回true

  4. 注意事项

    • 这种方法将空节点也纳入检查,确保结构对称

    • 可能存在的问题:如果树的节点值恰好等于INT_MIN,可能会误判(可改用其他标记方法如INT_MAX或额外标记)

递归遍历

cpp 复制代码
class Solution {
public:
    // 比较两个子树是否镜像对称的递归函数
    bool compare(TreeNode* left, TreeNode* right) {
        // 情况1:左节点为空但右节点不为空,不对称
        if (left == NULL && right != NULL) return false;
        // 情况2:左节点不为空但右节点为空,不对称
        else if (left != NULL && right == NULL) return false;
        // 情况3:左右节点都为空,对称(递归终止条件之一)
        else if (left == NULL && right == NULL) return true;
        // 情况4:左右节点都不为空,但值不相等,不对称
        else if (left->val != right->val) return false;

        // 执行到这里说明:左右节点都不为空,且数值相同
        // 需要继续递归检查下一层的子树
        
        // 比较外层:左子树的左子节点 vs 右子树的右子节点
        // 这是镜像对称的关键:外侧与外侧比较
        bool outside = compare(left->left, right->right);
        
        // 比较内层:左子树的右子节点 vs 右子树的左子节点
        // 镜像对称的另一个关键:内侧与内侧比较
        bool inside = compare(left->right, right->left);
        
        // 只有外侧和内测都对称,当前这对节点才算对称
        bool isSame = outside && inside;
        
        return isSame;
    }
    
    // 判断整棵树是否镜像对称的主函数
    bool isSymmetric(TreeNode* root) {
        // 如果根节点为空,空树被认为是对称的
        if (root == NULL) return true;
        
        // 从根节点的左右子树开始比较
        return compare(root->left, root->right);
    }
};

举例:

复制代码
    1
   / \
  2   2
   \   \
    3   3

第1步:调用 isSymmetric(root)

cpp 复制代码
root = 节点1
return compare(节点1的左子树(2), 节点1的右子树(2))

第2步:调用 compare(节点2, 节点2)

cpp 复制代码
参数: left = 节点2, right = 节点2

// 检查1:两个节点都不为空 → 通过
if (left == NULL && right != NULL) return false;  // 不执行
else if (left != NULL && right == NULL) return false;  // 不执行
else if (left == NULL && right == NULL) return true;  // 不执行

// 检查2:值相等 → 通过
else if (left->val != right->val) return false;  // 2 != 2? false,不执行

// 继续递归比较子树

第3步:递归比较子树

cpp 复制代码
// 比较外层:左子树的左子节点 vs 右子树的右子节点
bool outside = compare(left->left, right->right);
// left->left = 空,right->right = 节点3
// compare(空, 节点3)

// 比较内层:左子树的右子节点 vs 右子树的左子节点
bool inside = compare(left->right, right->left);
// left->right = 节点3,right->left = 空
// compare(节点3, 空)

第4步:执行 compare(空, 节点3)

cpp 复制代码
参数: left = 空, right = 节点3

// 检查第一个条件:
if (left == NULL && right != NULL) return false;
// left == NULL 成立,right != NULL 成立
// 所以返回 false

第5步:执行 compare(节点3, 空)

cpp 复制代码
参数: left = 节点3, right = 空

// 检查第二个条件:
else if (left != NULL && right == NULL) return false;
// left != NULL 成立,right == NULL 成立
// 所以返回 false

第6步:回到 compare(节点2, 节点2)

cpp 复制代码
bool outside = compare(空, 节点3) = false
bool inside = compare(节点3, 空) = false
bool isSame = outside && inside = false && false = false

return isSame = false

第7步:回到 isSymmetric

cpp 复制代码
return compare(root->left, root->right) = false

最终结果:返回 false

cpp 复制代码
isSymmetric(1)
  |
  v
compare(2, 2)
  |
  ├── outside: compare(空, 3) → false
  |      原因:左为空,右不为空 → 不对称
  |
  └── inside: compare(3, 空) → false
         原因:左不为空,右为空 → 不对称
  |
  v
false && false = false
相关推荐
JieE2121 天前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
JieE2122 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack202 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树2 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2123 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2123 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术3 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦3 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
用户497863050733 天前
(一)小红的数组操作
算法·编程语言