题 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. 二叉树的镜像(递归 / 辅助栈,清晰图解)