101. 对称二叉树
一、题目
给你一个二叉树的根节点 root
, 检查它是否轴对称。
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
提示:
- 树中节点数目在范围
[1, 1000]
内 -100 <= Node.val <= 100
**进阶:**你可以运用递归和迭代两种方法解决这个问题吗?
二、题解
方法一:递归
算法思路(建议对照题干里的图片理解)
要判断一棵二叉树是否轴对称,我们可以使用递归的方法。轴对称意味着该二叉树左右两侧镜像对称,即左子树的左子节点和右子树的右子节点相等,并且左子树的右子节点和右子树的左子节点相等。
我们可以定义一个辅助函数 isMirror
,该函数接受两个节点作为参数,然后递归地比较这两个节点及其子树是否镜像对称。如果这两个节点都为空,则它们是对称的;如果其中一个为空而另一个不为空,则它们不对称;如果两个节点都不为空,那么我们需要判断它们的值是否相等,并继续递归判断左右子树的对称性。
接下来,我们只需要调用 isMirror(root, root)
,其中 root
是二叉树的根节点,来判断整个二叉树是否轴对称。
具体实现
class Solution {
public:
bool isSymmetric(TreeNode* root) {
return isMirror(root, root);
}
bool isMirror(TreeNode* node1, TreeNode* node2) {
if (node1 == nullptr && node2 == nullptr) {
return true; // 两个空节点是对称的
}
if (node1 == nullptr || node2 == nullptr) {
return false; // 一个空节点一个非空节点不对称
}
// 比较当前节点的值,并递归判断左右子树的对称性
// 轴对称意味着左子树的左子节点和右子树的右子节点相等,并且左子树的右子节点和右子树的左子节点相等
return (node1->val == node2->val) &&
isMirror(node1->left, node2->right) &&
isMirror(node1->right, node2->left);
}
};
算法分析
- 时间复杂度:对于每个节点,我们最多访问其两个子节点,因此时间复杂度是 O(N),其中 N 是节点的数量。
- 空间复杂度:递归调用的栈空间取决于二叉树的高度,最坏情况下,树是一个链状结构,空间复杂度为 O(N)。在平均情况下,树的高度较小,空间复杂度较低。
总结
判断二叉树是否轴对称可以使用递归的方法。我们定义一个辅助函数 isMirror
,该函数用于递归比较两个节点及其子树是否镜像对称。根据节点是否为空,以及节点值是否相等,我们可以判断节点是否对称。然后,我们只需要调用 isMirror(root, root)
来判断整个二叉树是否轴对称。这个算法的时间复杂度是 O(N),最坏空间复杂度是 O(N)。
方法二、迭代
算法思路
-
我们可以使用迭代的方法来判断对称性,使用一个队列(deque)来辅助我们逐层遍历二叉树节点。首先将根节点两次入队,因为在一开始的时候,我们需要比较的是根节点的左子树和右子树。
-
在每一次循环中,我们从队列中取出两个节点node1和node2,并进行比较:
- 如果两个节点都为nullptr,说明当前层级上是对称的,继续下一次循环;
- 如果其中一个节点为nullptr而另一个节点不为nullptr,说明当前层级上不对称,直接返回false;
- 如果两个节点的值不相等,说明当前层级上不对称,直接返回false。
-
如果当前节点node1和node2的值相等,说明当前层级上是对称的,我们将node1的左子树和node2的右子树以及node1的右子树和node2的左子树按照相反的顺序入队,以便继续判断下一层级。
-
当队列为空时,说明二叉树的对称性已经判断完毕,没有发现不对称的部分,返回true。
具体实现
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isSymmetric(TreeNode* root) {
deque<TreeNode*> deq;
if(root == nullptr) return true;
deq.push_back(root);
deq.push_back(root);
while(!deq.empty()){
TreeNode *node1 = deq.front();
deq.pop_front();
TreeNode *node2 = deq.front();
deq.pop_front();
if(node1 == nullptr && node2 == nullptr) continue;
if(node1 == nullptr || node2 == nullptr) return false;
if(node1->val != node2->val) return false;
deq.push_back(node1->left);
deq.push_back(node2->right);
deq.push_back(node1->right);
deq.push_back(node2->left);
}
return true;
}
};
算法分析
- 时间复杂度: 假设二叉树中有n个节点,每个节点都需要进出队列一次,所以时间复杂度为O(n)。
- 空间复杂度: 使用了一个双端队列(deque)来辅助存储节点,最坏情况下可能存储n/2个节点,所以空间复杂度为O(n)。