《剑指 Offer》学习记录:题 27:二叉树的镜像

题 27:二叉树的镜像

题干

题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。——《剑指 Offer》P157

测试用例

二叉树的类定义如下(python):

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

例如传入的二叉树结构为:

则函数返回的二叉树的镜像的结构为:

分治法

方法思路

二叉树的镜像的特点在于,二叉树中的所有结点左右都要对调。这个问题可以用分治的思想来考虑,也就是把大问题分解为 n 个小问题。对于一个结点来说可以分为 2 个子问题,分别是左子树修改为其镜像,右子树修改为其镜像,接着只需要把左右子树调换即可。例如对于刚刚的二叉树,想要把结点 1 变为镜像,可以分解为将结点 2 和结点 3 修改为其镜像:

结点 2 和结点 3 修改为其镜像后,再交换结点 1 的左右子树。

题解代码

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if root == None:
            return None
        left = root.left
        root.left = self.mirrorTree(root.right)
        root.right = self.mirrorTree(left)
        return root

时空复杂度

设二叉树共有 n 个结点,算法需要遍历二叉树的所有结点,时间复杂度为 O(n)。
由于递归需要额外的空间保存状态,所以空间复杂度为 O(n)。

迭代法

方法思路

除了使用分治的思想,也可以把二叉树的镜像过程理解为对二叉树进行层序遍历,然后将每一层的序列颠倒。此时可以使用栈结构实现逆序,因为栈结构具有先进后出的特点,可以将一层的结点顺序颠倒。例如对于刚刚的二叉树,初始状态下只有根结点入栈:

将栈顶出栈,把结点 1 的左、右节点分别入栈,然后对调结点 1 的左右子树。

将结点 3 出栈,把结点 3 的左、右节点分别入栈,然后对调结点 3 的左右子树。

将结点 6 出栈,由于结点 6 是子叶节点,所以不需要进行其他操作。

将结点 2 出栈,把结点 2 的左、右节点分别入栈,然后对调结点 2 的左右子树。

将结点 5 出栈,由于结点 5 是子叶节点,所以不需要进行其他操作。将结点 4 出栈,由于结点 4 是子叶节点,所以不需要进行其他操作。最后栈空,表示算法结束,得到了原二叉树的镜像。

题解代码

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if root == None:
            return root
        stack = [root]
        while stack:
            node = stack.pop()
            if node.left != None:
                stack.append(node.left)
            if node.right != None:
                stack.append(node.right)
            node.left, node.right = node.right, node.left
        return root

时空复杂度

设二叉树共有 n 个结点,算法需要遍历二叉树的所有结点,时间复杂度为 O(n)。
由于需要额外一个栈结构作为辅助,所以空间复杂度为 O(n)。

参考资料

《剑指 Offer(第2版)》,何海涛 著,电子工业出版社
剑指 Offer 27. 二叉树的镜像(递归 / 辅助栈,清晰图解)

posted @ 2021-05-23 00:08  乌漆WhiteMoon  阅读(82)  评论(0编辑  收藏  举报