题目描述
给你一个二叉树的根节点 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
进阶:你可以运用递归和迭代两种方法解决这个问题吗?
思路
方法一:递归法
判断二叉树是否对称时本质上是要判断根节点的左子树和右子树是否可以相互翻转,如果可以相互翻转,那么这棵二叉树就是对称二叉树。在遍历的过程中,要同时遍历两棵树,并且比较的是两个子树的里侧和外侧的元素是否相等。
本题如果要使用递归法来解决的话只能使用“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等,只有后序遍历才能把比较底部孩子是否相等的信息返回给上一层,准确的来说是一个树的遍历顺序是左右中,另一个树的遍历顺序是右左中。
递归三部曲:
- 确定递归函数的参数和返回值。因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。返回值自然是bool类型。
- 确定终止条件。要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚。节点为空的情况有:(1)左节点为空,右节点不为空,不对称,return false;(2)左不为空,右为空,不对称 return false;(3)左右都为空,对称,返回true。节点都不为空的情况有:(1)左右都不为空,比较节点数值,不相同return false;(2)左右都不为空,比较节点数值,相同return true【需要进行处理的情况】。
- 确定单层递归的逻辑。单层递归的逻辑就是处理左右节点都不为空,且数值相同的情况。(1)比较二叉树外侧是否对称:传入左节点的左孩子,右节点的右孩子。(2)比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。(3)如果左右都对称就返回true ,有一侧不对称就返回false 。
方法二:迭代法
本题的迭代法可不是前中后序的迭代写法,因为本题的本质是判断两个树是否是相互翻转的,其实已经不是所谓二叉树遍历的前中后序的关系了。
这里我们可以使用队列来比较两个树(根节点的左右子树)是否相互翻转,但这不是层序遍历。
代码
C++版:
方法一:递归法
/**
* 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:
// 递归法,后序遍历
// 1.确定递归函数的参数和返回值
bool dfs(TreeNode* left,TreeNode* right){
// 2.确定终止条件
if(left==NULL && right!=NULL) return false;
else if(left!=NULL && right==NULL) return false;
else if(left==NULL && right==NULL) return true;
else if(left->val!=right->val) return false;
// 3.确定单层递归的逻辑
bool outside = dfs(left->left,right->right); // 左子树:左、 右子树:右
bool inside = dfs(left->right,right->left); // 左子树:右、 右子树:左
bool isSame = outside && inside; // 左子树:中、 右子树:中 (逻辑处理)
return isSame;
}
bool isSymmetric(TreeNode* root) {
bool result = dfs(root->left,root->right);
return result;
}
};
方法二:迭代法
/**
* 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) {
if (root == NULL) return true;
queue<TreeNode*> que;
que.push(root->left); // 将左子树头结点加入队列
que.push(root->right); // 将右子树头结点加入队列
while (!que.empty()) { // 接下来就要判断这两个树是否相互翻转
TreeNode* leftNode = que.front(); que.pop();
TreeNode* rightNode = que.front(); que.pop();
if (!leftNode && !rightNode) { // 左节点为空、右节点为空,此时说明是对称的
continue;
}
// 左右一个节点不为空,或者都不为空但数值不相同,返回false
if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {
return false;
}
que.push(leftNode->left); // 加入左节点左孩子
que.push(rightNode->right); // 加入右节点右孩子
que.push(leftNode->right); // 加入左节点右孩子
que.push(rightNode->left); // 加入右节点左孩子
}
return true;
}
};
Python版:递归法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
# 递归法,后序遍历
# 1.确定递归函数的参数和返回值
def dfs(self, left, right):
# 2.确定终止条件
if left == None and right != None: return False
elif left != None and right == None: return False
elif left == None and right == None: return True
elif left.val != right.val: return False
# 3.确定单层递归的逻辑
outside = self.dfs(left.left, right.right) #左子树:左、 右子树:右
inside = self.dfs(left.right, right.left) #左子树:右、 右子树:左
isSame = outside and inside #左子树:中、 右子树:中 (逻辑处理)
return isSame
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
return self.dfs(root.left, root.right)
需要注意的地方
1.注意终止条件中的最后一种情况,没有使用else,而是else if, 因为我们把以上情况都排除之后,剩下的就是左右节点都不为空,且数值相同的情况。