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
进阶:你可以运用递归和迭代两种方法解决这个问题吗?
方法一:递归
1.1 思路分析
二叉树关于第一个根节点轴对称,那么左子树的前序遍历和右子树的后序遍历正好是互逆的。
1.2 代码实现
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
List<Integer> preList = new LinkedList<Integer>();
List<Integer> postList = new LinkedList<Integer>();
// 第一个根节点是对称轴,如果存在就不用再考虑
preorder(root.left, preList); // 前序遍历 2 3 4
postorder(root.right, postList); // 后序遍历 4 3 2
int m=preList.size(), n=postList.size();
if (m != n) return false;
for (int i=0; i<m; i++){ // 如果两个序列是相反的,说明对称
if (preList.get(i) != postList.get(n-i-1)) return false;
}
return true;
}
public void preorder(TreeNode root, List<Integer> res){
if (root == null){
res.add(101); // 使用一个不在范围的数字代表null, 也可以用其他标志
return;
}
res.add(root.val);
preorder(root.left, res);
preorder(root.right, res);
}
public void postorder(TreeNode root, List<Integer> res){
if (root == null){ // 使用一个不在范围的数字代表null, 也可以用其他标志
res.add(101);
return;
}
postorder(root.left, res);
postorder(root.right, res);
res.add(root.val);
}
}
1.3 测试结果
1.4 复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(n)
方法二:递归 + 指针
2.1 思路分析
定义两个指针p和q,递归调用时两个指针的方向相反,如果q访问左节点,p便访问右节点。
2.2 代码实现
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
return check(root, root);
}
public boolean check(TreeNode p, TreeNode q){
if (p == null && q == null){
return true;
}
if (p == null || q == null){
return false;
}
return q.val==p.val && check(q.left, p.right) && check(q.right, p.left);
}
}
2.3 测试结果
2.4 复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(n)
方法三:迭代
3.1 思路分析
引入一个队列,这是把递归程序改写成迭代程序的常用方法。初始化时我们把根节点入队两次。每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。
3.2 代码实现
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
return check(root, root);
}
public boolean check(TreeNode p, TreeNode q){
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(p); // 第一次根节点
queue.offer(q); // 第二次根节点
while(!queue.isEmpty()){
p = queue.poll();
q = queue.poll();
if(p == null && q == null) continue;
if ((p==null || q==null) || p.val != q.val){
return false;
}
queue.offer(p.left);
queue.offer(q.right);
queue.offer(p.right);
queue.offer(q.left);
}
return true;
}
}
3.3 测试结果
3.4 复杂度
- 时间复杂度:O(n)
- 空间复杂度:O(n)