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
相关推荐
源代码•宸2 小时前
Golang原理剖析(string面试与分析、slice、slice面试与分析)
后端·算法·面试·golang·扩容·string·slice
派森先生2 小时前
排序算法-冒泡排序
算法·排序算法
静心问道2 小时前
排序算法分类及实现
算法·排序算法
2301_764441332 小时前
python实现罗斯勒吸引子(Rössler Attractor)
开发语言·数据结构·python·算法·信息可视化
码农三叔2 小时前
(7-3)自动驾驶中的动态环境路径重规划:实战案例:探险家的行进路线
人工智能·算法·机器学习·机器人·自动驾驶
飞Link2 小时前
【Water】数据增强中的数据标注、数据重构和协同标注
算法·重构·数据挖掘
漫随流水2 小时前
leetcode算法(559.N叉树的最大深度)
数据结构·算法·leetcode·二叉树
池塘的蜗牛2 小时前
NR PDSCH和CSI 正交导频设计
算法