leetcode
leetcode 101 ~ 150
从前序与中序遍历序列构造二叉树

从前序与中序遍历序列构造二叉树

难度:

标签:

题目描述

给定两个整数数组 preorderinorder ,其中 preorder 是二叉树的先序遍历inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

 

示例 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

 

提示:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorder 和 inorder 均 无重复 元素
  • inorder 均出现在 preorder
  • preorder 保证 为二叉树的前序遍历序列
  • inorder 保证 为二叉树的中序遍历序列

代码结果

运行时间: 224 ms, 内存: 19.1 MB


/*
 * 解题思路:
 * 1. 通过流处理查找根节点在中序遍历中的位置。
 * 2. 使用流构建左右子树。
 * 3. 递归构建整个树。
 */
 
import java.util.*;
import java.util.stream.*;
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
 
public class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder.length == 0) return null;
        int rootVal = preorder[0];
        TreeNode root = new TreeNode(rootVal);
        int inRootIndex = IntStream.range(0, inorder.length)
                                   .filter(i -> inorder[i] == rootVal)
                                   .findFirst()
                                   .orElse(-1);
        int[] leftInorder = Arrays.copyOfRange(inorder, 0, inRootIndex);
        int[] rightInorder = Arrays.copyOfRange(inorder, inRootIndex + 1, inorder.length);
        int[] leftPreorder = Arrays.stream(preorder)
                                   .skip(1)
                                   .limit(leftInorder.length)
                                   .toArray();
        int[] rightPreorder = Arrays.stream(preorder)
                                    .skip(1 + leftInorder.length)
                                    .toArray();
        root.left = buildTree(leftPreorder, leftInorder);
        root.right = buildTree(rightPreorder, rightInorder);
        return root;
    }
}

解释

方法:

该题解使用递归的方式,根据前序遍历和中序遍历的特点构建二叉树。首先,前序遍历的第一个元素一定是根节点。然后,在中序遍历中找到根节点的位置,根据根节点将中序遍历序列分为左右两部分,分别对应根节点的左右子树。接着,递归地对左右子树进行同样的处理,直到所有节点都被处理完。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
在构建二叉树的过程中,如果节点值存在重复,当前的逻辑是否能正确处理?
不,当前的逻辑无法正确处理节点值存在重复的情况。在中序遍历中查找根节点的位置时,代码只查找并使用第一个匹配的节点。如果存在重复的节点值,这可能导致错误地划分左右子树。构造二叉树的算法通常假设树中的所有节点值是唯一的,因为这是二叉树中节点标识的基础。如果要处理重复值,需要其他机制来唯一确定节点位置,或者更改题目条件确保节点值的唯一性。
🦆
递归构建子树时,如何确保preorder和inorder数组中的元素范围正确对应到子树的结构上?
递归构建子树时,正确对应preorder和inorder数组中的元素范围至关重要。这通过以下几个步骤确保:1) 使用前序遍历的第一个元素确定根节点。2) 在中序遍历中找到该根节点的索引,这个索引将中序遍历分为左右两部分,对应左右子树。3) 根据中序遍历中左子树的长度来确定前序遍历中左子树和右子树的元素范围。4) 递归调用自身来构建左子树和右子树,每次传递正确更新的索引范围。这种方法保证了每次递归调用都正确地映射到子树的结构上。
🦆
在递归构建左右子树时,是否有可能通过改进算法减少重复的操作或优化递归过程?
是的,可以通过一些优化来减少重复操作或提高递归过程的效率。一个常见的改进是使用哈希表来存储中序遍历中每个值与其索引的映射,这样可以在O(1)时间内查找根节点的索引,而不是每次都进行线性搜索。此外,递归过程中可以通过更好地管理索引而不是复制数组片段来减少空间消耗。这些优化可以显著提高算法的时间和空间效率。

相关问题

从中序与后序遍历序列构造二叉树

给定两个整数数组 inorderpostorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

 

示例 1:

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

示例 2:

输入:inorder = [-1], postorder = [-1]
输出:[-1]

 

提示:

  • 1 <= inorder.length <= 3000
  • postorder.length == inorder.length
  • -3000 <= inorder[i], postorder[i] <= 3000
  • inorder 和 postorder 都由 不同 的值组成
  • postorder 中每一个值都在 inorder 中
  • inorder 保证是树的中序遍历
  • postorder 保证是树的后序遍历