leetcode
leetcode 801 ~ 850
根据前序和后序遍历构造二叉树

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

难度:

标签:

题目描述

给定两个整数数组,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 是同一棵二叉树的前序遍历和后序遍历

代码结果

运行时间: 20 ms, 内存: 16.2 MB


/*
 * The problem is to construct a binary tree from given preorder and postorder traversals using Java Streams.
 * We will use a helper function that takes indices of the current subarray in preorder and postorder arrays.
 * Using the properties of preorder and postorder traversal, we will recursively construct the tree.
 */

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

public class Solution {
    private int preIndex = 0;
    private int[] preorder;
    private int[] postorder;
    private Map<Integer, Integer> postIndexMap;

    public TreeNode constructFromPrePost(int[] preorder, int[] postorder) {
        this.preorder = preorder;
        this.postorder = postorder;
        this.postIndexMap = IntStream.range(0, postorder.length)
                                     .boxed()
                                     .collect(Collectors.toMap(i -> postorder[i], i -> i));
        return buildTree(0, postorder.length - 1);
    }

    private TreeNode buildTree(int left, int right) {
        if (left > right || preIndex >= preorder.length) {
            return null;
        }
        TreeNode root = new TreeNode(preorder[preIndex++]);
        if (left == right || preIndex >= preorder.length) {
            return root;
        }
        int postIndex = postIndexMap.get(preorder[preIndex]);
        root.left = buildTree(left, postIndex);
        root.right = buildTree(postIndex + 1, right - 1);
        return root;
    }
}

解释

方法:

这个题解使用递归的方法来构建二叉树。主要思路是根据前序遍历和后序遍历的特点,找到根节点和左右子树的范围,递归地构建左右子树。具体来说: 1. 前序遍历的第一个元素是根节点 2. 在后序遍历中找到前序遍历第二个元素的位置,可以得到左子树的大小 3. 根据左子树大小,可以确定前序遍历和后序遍历中左右子树的范围 4. 递归地构建左子树和右子树 5. 返回根节点

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在构建二叉树的过程中,递归函数的终止条件是前序遍历的左指针大于右指针,这是为什么?
在构建二叉树的过程中,当前序遍历的左指针大于右指针时,这表示当前递归处理的子数组不包含任何元素,即当前递归范围内没有节点可以构建,故应终止递归。此条件是递归终止的基本逻辑,确保不会对空数组进行无效的操作或尝试访问不存在的数组元素。
🦆
题解中提到可以返回任何一个有效的二叉树,这是否意味着前序和后序遍历序列可能对应多个不同的二叉树结构?如果是,能否给出一个具体的例子?
是的,前序和后序遍历序列可能对应多个不同的二叉树结构,特别是在二叉树的结构不是完全确定的情况下。例如,对于前序遍历序列 [2, 1] 和后序遍历序列 [1, 2],可以构建两种不同的二叉树结构:一种是根节点为2,左子树为1,右子树为空;另一种是根节点为2,左子树为空,右子树为1。这两种结构的前序和后序遍历结果相同,但二叉树结构不同。
🦆
在递归构建二叉树时,如何确保每次递归调用正确无误地分割左右子树?
为了正确无误地分割左右子树,解题策略中利用了前序和后序遍历的特点。在前序遍历中,根节点后的第一个元素代表左子树的根节点;在后序遍历中,此左子树的根节点的位置可以标识出整个左子树的范围。通过在后序遍历中找到这个左子树根节点的位置,我们可以计算出左子树的大小,然后根据这个大小在前序和后序遍历中分别划分出左右子树的元素范围。这样每次递归都能准确地处理相应的子树。
🦆
哈希表`postorder_index`的作用是什么,在解题过程中它如何帮助提高效率?
哈希表`postorder_index`存储了后序遍历中每个元素的索引位置,这样在需要找到任何元素在后序遍历中的位置时,可以直接通过哈希表以常数时间O(1)完成查找,而不需要遍历整个后序遍历数组来搜索元素,从而避免了O(n)的时间复杂度。在递归构建二叉树时,这种快速查找显著提高了效率,特别是在频繁地确定子树范围时,哈希表的作用尤为重要。

相关问题