vlambda博客
学习文章列表

刷题小组|倒计时9天:对称二叉树

题目

今天的题目是:对称二叉树

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

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3

3241423

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

    1
   / \
  2   2
   \   \
   3    3

23123

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

请大家独立思考并完成,欢迎在刷题小组交流群中讨论学习。

大家加油!

(以下内容先别看!)

解题思路(递归)

一般来说,涉及到二叉树的问题,我们可以从递归、迭代以及前中后遍历的顺序来考虑。

首先看递归的思想:

如果一颗镜像二叉树,其左右子树都是镜像二叉树吗?

仔细想一想,实际不是的。比如下面这个例子:

首先它是一颗镜像二叉树,其左子树(红)和右子树(黄)是对称的;但是左子树本身并不是镜像二叉树,因为左子树的左子树(蓝)和右子树(绿)不是对称的;但是左子树的左子树(蓝)和右子树的右子树镜像对称。

因此,一颗镜像二叉树应当满足如下条件:

  • 其左右子树的根节点值相同
  • 其左子树的左子树与右子树的右子树镜像对称;其左子树的右子树与右子树的左子树镜像对称

我们将根节点root的左子树记为left,右子树记为right。基于这样的条件,我们使用递归,则:

  • 终止条件:left.val != right.val不为镜像;或者left与right都为空则返回True;或者left与right中有一个为空则返回False
  • 如何递归:递归的比较left.left和right.right;递归的比较left.right和right.left
class Solution(object):
    def isSymmetric(self, root):
        if not root: return True
        def dfs(left, right):
            if not (left or right): return True
            if not (left and right): return False
            if left.val != right.val: return False
            return dfs(left.left, right.right) and dfs(left.right, right.left)
    return dfs(root.left, root.right)            

解题思路(用队列进行迭代)

同样的思路,我们可以用递归解,也可以用迭代解。

用队列来实现,首先从队列中拿出两个节点left和right进行比较,将left.left节点和right.right节点放入队列;将left.right和right.left放入队列。

class Solution(object):
    def isSymmetric(self, root):
        if not root or not(root.left or root.right): 
            return True
        # 用队列保存节点
        queue = [root.left, root.right]
        while queue:
            # 从队列中取出两个节点并比较是否相等
            left = queue.pop(0)
            right = queue.pop(0)
            # 如果两个节点都为空,就继续循环
            if not (left or right): continue
            # 如果两者有一个为空就返回false
            if not (left and right): return False
            if left.val != right.val: return False
            # 将左节点的左孩子,右节点的右孩子放入队列
            queue.append(left.left)
            queue.append(right.right)
            # 将左节点的右孩子,右节点的左孩子放入队列
            queue.append(left.right)
            queue.append(right.left)
        return True

解题思路(遍历)

对于一棵镜像二叉树,对这棵树根节点的左子树进行前序遍历: pre_order = [2,3,5,6,4,7,8];

接着我们对这棵树根节点的右子树进行后序遍历:post_order = [8,7,4,6,5,3,2]

根据两次遍历我们不难发现 post_order 就是 pre_order的逆序,其实这也是对称二叉树的一个性质,根据这一点就不难写出代码了。

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        bli = []    # 用来存左子树的前序遍历
        fli = []    # 用来存右子树的后续遍历
        if not root: return True
        if not (root.left or root.right): return True
        if root.left and root.right:
            self.pre_order(root.left, bli)
            self.post_order(root.right, fli)
            fli.reverse()
            if bli == fli: return True
            elsereturn False
    
    def pre_order(self, root, li):
        if root:
            li.append(root.val)
            self.pre_order(root.left, li)
            self.pre_order(root.right, li)
        elif root is None:
            li.append(None)
            
    def post_order(self,root,li):  
        if root:
            self.post_order(root.left,li)
            self.post_order(root.right,li)
            li.append(root.val)
        elif root == None:
            li.append(None)