根据先序遍历和后序遍历构建二叉树

关于先序遍历、中序遍历、后序遍历的定义可以参考这篇博客二叉树的遍历规则

目前能够百度到的问题大多都是根据(先序&中序)或(中序&后序)序列构建唯一二叉树,其中贴出一些提供思路的博客:二叉树的前序中序后序遍历相互求法

但是这篇博客并没有给出**(前序&后序)**的求解方法。事实上,根据前序和后序构建的二叉树不唯一,理由是前序与后序都没有明确规定节点间的父子关系,例如下图所示:
前序后序图示
下面给出已知前序&后序序列,求任一解的方法。该题同时出现于LeetCode Weekly Contest 98

LeetCode 889. Construct Binary Tree from Preorder and Postorder Traversal

Return any binary tree that matches the given preorder and postorder
traversals. Values in the traversals pre and post are distinct
positive integers.

Example 1: Input: pre = [1,2,4,5,3,6,7], post = [4,5,2,6,7,3,1]
Output: [1,2,3,4,5,6,7]

该题给出的解如下图所示:
LeetCode Demo


解题思路:
还是可以根据一般的思路,采用递归思想,对于每一个先序序列,划分出对应的根节点、左子树、右子树范围即可自上而下构建出二叉树。
例如对于上例中的先序序列[1,2,4,5,3,6,7],第一个节点一定为根节点,第2到第i个节点为左子树,第i+1到最后一个节点为右子树,那么问题就可以简化为:如何确定左右子树分界点?
思路

对于这个简化过后的问题,从后序遍历序列上很容易得到答案:
分解过程

因此,可以写出递归函数的核心代码:

#伪代码,用于理解思路
def func(pre, post):   #pre为先序序列,post为后序序列
    ...
    node = Node(pre[0])
    index = find_index(post, pre[1].val)  #查找分割点下标
    node.left = func(pre[1:index+2], post[:i+1])
    node.right = func(pre[index+2:], post[i+1:-1])
    return node

对于该题的完整解法如下所示(python):

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

class Solution(object):
    def constructFromPrePost(self, pre, post):
        """
        :type pre: List[int]
        :type post: List[int]
        :rtype: TreeNode
        """
        def fun(p, t):
            if len(p) == 0:
                return None
            node = TreeNode(p[0])
            if len(p) == 1:
                return node
            i = 0
            while p[1] != t[i]:
                i += 1
            node.left = fun(p[1:i+2], t[:i+1])
            node.right = fun(p[i+2:], t[i+1:-1])
            return node
        return fun(pre, post)

拓展问题:如何输出所有满足要求的二叉树?
以上。

  • 14
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值