📝 题目描述

题目链接对称二叉树

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

示例:

示例 1:

1
2
输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:

1
2
输入:root = [1,2,2,null,3,null,3]
输出:false

提示:

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

💡 解题思路

方法一:递归

判断一棵树是否对称,本质上是判断它的左子树和右子树是否是相互镜像的。

如果同时满足下面的条件,两个树互为镜像:

  • 它们的两个根结点具有相同的值
  • 每个树的右子树都与另一个树的左子树镜像对称

我们可以实现这样一个递归函数,通过“同步移动”两个指针的方法来遍历这棵树。

首先获取根节点的左节点指针 left 和右节点指针 right,然后进入函数,首先比较这两个指针是否相同,然后left->left和right->right进行比较,left->right和right->left进行比较。即这两个指针移动方向相反,随后 left 左移时,right 右移;left 右移时,right 左移。每次检查当前 leftright 节点的值是否相等,如果相等再判断左右子树是否对称。

方法二:迭代

首先我们引入一个队列,这是把递归程序改写成迭代程序的常用方法。

初始化时我们把根节点的两个子节点入队,循环中每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。

🔧 代码实现

1、递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (root == nullptr) return true;
return isMirror(root->left, root->right);
}
bool isMirror(TreeNode* left, TreeNode* right) {
// 如果两个节点都为空,则是对称的
if (left == nullptr && right == nullptr) return true;
// 如果其中一个为空,另一个不为空,或者两个节点的值不相等,则不对称
if (left == nullptr || right == nullptr || left->val != right->val) return false;

// 递归比较:左子树的左节点与右子树的右节点;左子树的右节点与右子树的左节点
return isMirror(left->left, right->right) && isMirror(left->right, right->left);
}
};

2、迭代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (root == nullptr) return true;

queue<TreeNode*> qu;
qu.push(root->left);
qu.push(root->right);

while (!qu.empty()) {
TreeNode* leftNode = qu.front(); qu.pop();
TreeNode* rightNode = qu.front(); qu.pop();

// 两个都为空,继续检查队列中的下一对
if (leftNode == nullptr && rightNode == nullptr) continue;
// 只有一个为空,或者值不相等,直接返回 false (快速失败)
if (leftNode == nullptr || rightNode == nullptr || leftNode->val != rightNode->val) {
return false;
}

// 按镜像对称的顺序将子节点成对入队
// 外侧节点对
qu.push(leftNode->left);
qu.push(rightNode->right);
// 内侧节点对
qu.push(leftNode->right);
qu.push(rightNode->left);
}

return true;
}
};

📊 复杂度分析

1、暴力解法

  • 时间复杂度O(N)O(N),这里遍历了整棵树。
  • 空间复杂度O(H)O(H),其中 H 为树的高度。这是由于递归调用栈的开销。最坏情况下(树退化成链表)为 O(N)O(N),而在平衡二叉树下为 O(logN)O(logN)

2、优化解法

  • 时间复杂度O(N)O(N),这里遍历了整棵树。
  • 空间复杂度O(N)O(N),这里需要用一个队列来维护节点,每个节点最多进队一次,出队一次,队列中最多不会超过 n 个点。

🎯 总结

  • 核心思想:记住镜像移动的方法。