题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},请重建二叉树并返回。
解题之前,不妨先回顾一下二叉树的前序(先序)和中序遍历。先序遍历二叉树的操作定义:(1)访问根结点;(2)遍历左子树;(3)遍历右子树,如图1(a)所示。中序遍历二叉树的操作定义:(1)遍历左子树;(2)访问根节点;(3)遍历右子树,如图1(b)所示。
利用题目中先序遍历序列和中序遍历序列可手动推导该二叉树模型,推导的中心思想为:1、根据先序遍历序列得到根节点的位置,即首项,因为先序遍历首先遍历二叉树的根节点,2、然后配合中序遍历序列判断根节点的左右子树序列,如图2(a)所示。下面看详细的推导步骤:
步骤一:确定根节点1。根据先序遍历序列得出根节点1,然后配合中序遍历序列得出左右子树,如图2(a)所示,但是此时无法确定左右子树序列中哪项为根结点1的叶结点。我们可以单独考虑根节点1的左右子树,这里我们考虑左子树序列,即图2(a)中红色虚线左侧序列。
步骤二:确定结点2。如图3(a)所示,将根节点1的左子树的前序和中序序列截取出来,利用步骤一的推导方法判断该序列的根节点和左右子树,注意,该中序遍历序列中结点2右边没有项,说明结点2无右子树。
步骤三:确定结点4。接着把结点2左子树的前序和中序序列截取出来,根据先序遍历序列判断出结点4为结点7的根节点,然后根据中序遍历序列判断出结点7为结点4的右子树。
根节点1的右子树推导原理与左子树推导原理一样,大家可以试着推导一下,最终该题的二叉树模型如图5所示。
手动推导二叉树模型的过程有助于解题,回顾一下推导过程,是将一个复杂的二叉树序列逐渐分成若干个小的二叉树序列,直到小的二叉树序列能确定自己的左右子树。其实该过程就是一个递归,递归是解决问题的一种方法,其原则是:1、整个递归有终止条件:递归应该在什么时候结束。2、找返回值:应该给上一级返回什么信息。3、本递归应该做什么:在这一级递归中,应该完成什么任务。
这么说好像很抽象,我们以题目为例子,看看怎样使用递归。1、找终止条件:什么情况下递归结束?当然是树为空的时候,此时没有子树序列,递归就结束了。2、找返回值:应该返回什么?从图2(b),3(b)和4(b)可以看出从每一级得到的信息是这一级对应的根节点,因此返回值应该是当前树的根节点。3、本递归应该做什么:在步骤一二三中判断根节点,接着判断左右子树,本题是要重建二叉树,因此在每级递归中,将左右子树连接在根节点上即可。
完整代码如下:
# -*- coding:utf-8 -*-
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
# write code here
#递归终止条件
if not pre or not tin:
return None
#构造根节点,寻找左右子树的分界线
root = TreeNode(pre[0])
n = tin.index(pre[0])
#构造左右子树,递归调用
root.left = self.reConstructBinaryTree(pre[1:n + 1], tin[:n])
root.right = self.reConstructBinaryTree(pre[n + 1:], tin[n + 1:])
#返回根节点
return root
参考文献:
1、数据结构(C语言版),严蔚敏,2015
2、Python算法详解,张玲玲,2019
3、Python数据结构与算法分析,布拉德利.米勒,戴维.拉努姆,2019
4、剑指offer python实现 66道算法题,木信,2018
5、剑指面试题重建二叉树,挪罗儿,2020
6、递归三部曲,三年一梦,2019