101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
    1
   / \
  2   2
 / \ / \
3  4 4  3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
    1
   / \
  2   2
   \   \
   3    3
 

方法一:递归
二叉树的遍历问题最容易想到的就是递归,因为子树结构和整棵树都一样,可以用相同的方法递归遍历。

  1. 根结点为空,直接返回true
  2. 根结点不为空,比较左右子树。分三种情况:
    1. 左右子树都为空,返回true。
    2. 左右子树只有一个为空,返回false。
    3. 当左右子树都不为空,比较左右子树的根结点是否相同,相同则分别递归比较左子树的左子树和右子树的右子树,左子树的右子树和右子树的左子树。只有三者都为true 时,才返回true。
var isSymmetric = function(root) {
    if(root == null) return true;

    let isCommon = function(left,right){
        if(left == null) return right == null;
        if(right == null) return false;
        return left.val == right.val && isCommon(left.left,right.right) && isCommon(left.right,right.left);
    };

    return isCommon(root.left,root.right);
};

复杂度分析
假设树上一共 n 个节点。

  • 时间复杂度:这里遍历了这棵树,渐进时间复杂度为 O(n)。
  • 空间复杂度:这里的空间复杂度和递归使用的栈空间有关,这里递归层数不超过n,故渐进空间复杂度为 O(n)。

方法二:迭代
首先我们引入一个队列,这是把递归程序改写成迭代程序的常用方法。初始化时我们把左右子树的根结点入队。每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。

  • 根为空,返回true。
  • 维护一个队列,初始化时把根节点(如果存在)的左右子树入列。
  • 每次出队两个节点,比较是否对称。如果不对称,那整个树就不对称,结束BFS,如果对称,则下一对节点入列。

哪些情况不对称:

  • 一个为 null 一个不为 null,直接返回false。
  • 都存在,但 root 值不同,直接返回 false。

都为空时继续下一对节点的比较。直到队列为空遍历结束。对称时下一对节点入队的顺序根据二叉树的结构:左子树的左子树和右子树的右子树,左子树的右子树和右子树的左子树。

var isSymmetric = function(root) {
    if(root == null) return true;
    
    let queue = [];
    queue.push(root.left,root.right);
    while(queue.length){
        let left = queue.shift();
        let right  = queue.shift();
        if(left == null && right == null) continue;
        if((left == null || right == null) || left.val !== right.val) {
            return false;
        }
        queue.push(left.left,right.right,left.right,right.left);
    }
    return true;
};

复杂度分析

  • 时间复杂度:O(n),同「方法一」。
  • 空间复杂度:这里需要用一个队列来维护节点,每个节点最多进队一次,出队一次,队列中最多不会超过 n个点,故渐进空间复杂度为 O(n)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值