LeetCode 题解工作台

根据前序和后序遍历构造二叉树

给定两个整数数组, preorder 和 postorder ,其中 preorder 是一个具有 无重复 值的二叉树的前序遍历, postorder 是同一棵树的后序遍历,重构并返回二叉树。 如果存在多个答案,您可以返回其中 任何 一个。 示例 1: 输入: preorder = [1,2,4,5…

category

5

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

中等 · 数组·哈希·扫描

bolt

答案摘要

前序遍历的顺序是:根节点 -> 左子树 -> 右子树,后序遍历的顺序是:左子树 -> 右子树 -> 根节点。 因此,二叉树的根节点一定是前序遍历的第一个节点,也是后序遍历的最后一个节点。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 数组·哈希·扫描 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给定两个整数数组,preorder 和 postorder ,其中 preorder 是一个具有 无重复 值的二叉树的前序遍历,postorder 是同一棵树的后序遍历,重构并返回二叉树。

如果存在多个答案,您可以返回其中 任何 一个。

 

示例 1:

输入:preorder = [1,2,4,5,3,6,7], postorder = [4,5,2,6,7,3,1]
输出:[1,2,3,4,5,6,7]

示例 2:

输入: preorder = [1], postorder = [1]
输出: [1]

 

提示:

  • 1 <= preorder.length <= 30
  • 1 <= preorder[i] <= preorder.length
  • preorder 中所有值都 不同
  • postorder.length == preorder.length
  • 1 <= postorder[i] <= postorder.length
  • postorder 中所有值都 不同
  • 保证 preorder 和 postorder 是同一棵二叉树的前序遍历和后序遍历
lightbulb

解题思路

方法一:递归

前序遍历的顺序是:根节点 -> 左子树 -> 右子树,后序遍历的顺序是:左子树 -> 右子树 -> 根节点。

因此,二叉树的根节点一定是前序遍历的第一个节点,也是后序遍历的最后一个节点。

接下来,我们需要确定二叉树的左子树范围和右子树范围。

如果二叉树有左子树,那么左子树的根节点一定是前序遍历的第二个节点;如果二叉树没有左子树,那么前序遍历的第二个节点一定是右子树的根节点。由于这两种情况下,后序遍历的结果是一样的,因此,我们可以把前序遍历的第二个节点作为左子树的根节点,然后找到它在后序遍历中的位置,这样就确定了左子树的范围。

具体地,我们设计一个递归函数 dfs(a,b,c,d)dfs(a, b, c, d),其中 [a,b][a, b] 表示前序遍历的范围,而 [c,d][c, d] 表示后序遍历的范围。这个函数的功能是根据前序遍历 [a,b][a, b] 和后序遍历 [c,d][c, d] 构造出二叉树的根节点。那么答案就是 dfs(0,n1,0,n1)dfs(0, n - 1, 0, n - 1),其中 nn 是前序遍历的长度。

函数 dfs(a,b,c,d)dfs(a, b, c, d) 的执行步骤如下:

  1. 如果 a>ba > b,说明范围为空,直接返回空节点。
  2. 否则,我们构造一个新的节点 rootroot,它的值为前序遍历中的第一个节点的值,也就是 preorder[a]preorder[a]
  3. 如果 aa 等于 bb,说明 rootroot 没有左子树也没有右子树,直接返回 rootroot
  4. 否则,左子树的根节点的值为 preorder[a+1]preorder[a + 1],我们在后序遍历中找到 preorder[a+1]preorder[a + 1] 的位置,记为 ii。那么左子树的节点个数 m=ic+1m = i - c + 1,由此可知左子树在前序遍历中的范围是 [a+1,a+m][a + 1, a + m],后序遍历中的范围是 [c,i][c, i],右子树在前序遍历中的范围是 [a+m+1,b][a + m + 1, b],后序遍历中的范围是 [i+1,d1][i + 1, d - 1]
  5. 知道了左右子树的范围,我们就可以递归地重建左右子树,然后将左右子树的根节点分别作为 rootroot 的左右子节点。最后返回 rootroot

在函数 dfs(a,b,c,d)dfs(a, b, c, d) 中,我们需要用到一个哈希表 pospos,它存储了后序遍历中每个节点的位置。在函数的开头,我们可以先计算出这个哈希表,这样就可以在 O(1)O(1) 的时间内找到任意节点在后序遍历中的位置。

时间复杂度 O(n)O(n),空间复杂度 O(n)O(n)。其中 nn 是节点数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def constructFromPrePost(
        self, preorder: List[int], postorder: List[int]
    ) -> Optional[TreeNode]:
        def dfs(a: int, b: int, c: int, d: int) -> Optional[TreeNode]:
            if a > b:
                return None
            root = TreeNode(preorder[a])
            if a == b:
                return root
            i = pos[preorder[a + 1]]
            m = i - c + 1
            root.left = dfs(a + 1, a + m, c, i)
            root.right = dfs(a + m + 1, b, i + 1, d - 1)
            return root

        pos = {x: i for i, x in enumerate(postorder)}
        return dfs(0, len(preorder) - 1, 0, len(postorder) - 1)
speed

复杂度分析

指标
时间O(n)
空间O(n)
psychology

面试官常问的追问

外企场景
  • question_mark

    Ability to handle recursive problems efficiently.

  • question_mark

    Understanding of hash maps and their applications in tree construction.

  • question_mark

    Proficiency in managing multiple traversal patterns in binary trees.

warning

常见陷阱

外企场景
  • error

    Not correctly handling recursive base cases, leading to incorrect tree construction.

  • error

    Misunderstanding how to split the preorder and postorder arrays into subtrees.

  • error

    Inefficient lookup or missing hash map optimization for faster element positions.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Consider cases with trees containing only one node.

  • arrow_right_alt

    Explore variations with non-distinct values in the arrays.

  • arrow_right_alt

    Test the algorithm with the maximum allowed input size (30 nodes).

help

常见问题

外企场景

根据前序和后序遍历构造二叉树题解:数组·哈希·扫描 | LeetCode #889 中等