前端刷题路-Day78:对称二叉树(题号101)

406 阅读3分钟

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战

对称二叉树(题号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

进阶:

你可以运用递归和迭代两种方法解决这个问题吗?

链接

leetcode-cn.com/problems/sy…

解释

这题啊,这题是经典遍历二叉树。

不过遍历的时候需要注意,不能一口气遍历完左子树,然后遍历右子树,再将右子树的遍历结果反转,进行这样的操作后可以通过99%的测试用例,但依旧有1%无法成功。

为什么会这样?因为这里的对称二叉树是镜像的操作,不管使用前序、中序、后序哪种遍历方式,反转遍历结果的不会是镜像的,有些特殊的测试用例是无法通过的,别问为什么,笔者试过。

剩下的办法就是只能一个节点一个节点的对比了,如果有子节点,就反向对比子节点,那拿第一个例子来说,一开始肯定会比较左右子树的2节点,发现二者一样,接下来就应该比较左子树2节点的左子树和右子树2节点的右子树,依次类推,从而形成镜像的比较。

这样做不仅仅能拿到正确的结果,还可以再遇到不相同节点时提前终止比较,相较于一次性拿到所有节点值的做法可以节省一部分性能。

下面看看代码。

自己的答案

更好的方法(递归)

相对来说递归的方法总是比迭代要简单一些,所以就先说递归吧,整体思路就是从根节点的左右节点开始,进行镜像比较👇:

function isSymmetric(root) {
  function check(p, q) {
    if (!p && !q) return true
    if (!p || !q) return false
    return p.val === q.val && check(p.left, q.right) && check(p.right, q.left)
  }
  return check(root.left, root.right)
}

比较过程主要分三种:

  • pq都是null,证明二者相同,返回true
  • p或者q有一个是null,证明二者不相同,返回false
  • p.valq.val的值是否相同,返回true或者false

完成这三步的比较即可确定当前两个节点的值是否相同,接下来交叉比较二者的左右节点,这就完事了。

更好的方法(迭代)

迭代和平时遍历二叉树差不多,都需要借助一个栈来存储当前的节点。

在开始时,先将两个节点推入栈中,之后开始迭代,将两个节点依次取出来,对二者的值进行比较,比较过程和递归一样,完成比较发现没问题后,将二者的左右节点有序的推入到栈中,等待下依次迭代的开始。

function isSymmetric(root) {
  function check(p, q) {
    const arr = [p, q]
    while (arr.length) {
      p = arr.shift()
      q = arr.shift()
      if (!p && !q) continue
      if ((!p || !q)  || (p.val !== q.val)) return false
      arr.push(q.left)
      arr.push(p.right)
      arr.push(q.right)
      arr.push(p.left)
    }
    return true
  }
  return check(root.left, root.right)
}


PS:想查看往期文章和题目可以点击下面的链接:

这里是按照日期分类的👇

前端刷题路-目录(日期分类)

经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇

前端刷题路-目录(题型分类)