150NeetCode 150

58.Construct Binary Tree from Preorder and Inorder Traversal

MediumBlind 75Trees Ā· 13/15

Problem

Given two integer arrays preorder and inorder, where preorder is the pre-order traversal of a binary tree and inorder is the in-order traversal of the same tree, reconstruct and return the tree.

All values are unique, which is what makes the reconstruction unambiguous.

Examples

Input:  preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
Input:  preorder = [-1], inorder = [-1]
Output: [-1]

Constraints

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorder and inorder consist of unique values.
  • Each value of inorder also appears in preorder, and preorder is guaranteed to be the pre-order traversal of the tree (likewise for inorder).

šŸ’” Key Insight

The first element of a pre-order range is that subtree's root. Finding the root in the in-order range splits it: everything to its left is the left subtree, everything to its right is the right subtree, and the size of the left part tells us where the left subtree's pre-order range ends. A hash map from value to in-order index makes each split O(1), so the whole build is O(n).

Brute Force (Linear Search + Array Slicing)

TimeO(n²)SpaceO(n²)

Intuition

Apply the split rule directly: take preorder[0] as the root, search for it in inorder to find mid, then copy out the four sub-arrays and recurse. The left subtree has mid nodes, so its pre-order slice is preorder[1 .. mid] and its in-order slice is inorder[0 .. mid - 1].

Algorithm

  1. If preorder is empty, return null.
  2. root = new TreeNode(preorder[0]).
  3. Find mid such that inorder[mid] == root.val (linear scan).
  4. root.left = build(preorder[1 .. mid], inorder[0 .. mid-1]).
  5. root.right = build(preorder[mid+1 .. n-1], inorder[mid+1 .. n-1]).
  6. Return root.

Visualization

preorder = [3 | 9 | 20 15 7]      inorder = [9 | 3 | 15 20 7]
            root left  right                  left root right

left : preorder [9],        inorder [9]         -> leaf 9
right: preorder [20,15,7],  inorder [15,20,7]   -> root 20, left 15, right 7

Code

java
import java.util.Arrays;

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder.length == 0) {
            return null;
        }
        TreeNode root = new TreeNode(preorder[0]);
        int mid = 0;
        while (inorder[mid] != root.val) {
            mid++; // linear search for the root in inorder
        }
        // left subtree has `mid` nodes
        root.left = buildTree(
            Arrays.copyOfRange(preorder, 1, mid + 1),
            Arrays.copyOfRange(inorder, 0, mid));
        root.right = buildTree(
            Arrays.copyOfRange(preorder, mid + 1, preorder.length),
            Arrays.copyOfRange(inorder, mid + 1, inorder.length));
        return root;
    }
}

Complexity

  • Time: O(n²) — each call does an O(n) search and O(n) copying; a skewed tree has n levels.
  • Space: O(n²) — copied arrays across all recursion levels in the skewed case.

Complexity Comparison

Approach Time Space
Brute Force (Linear Search + Array Slicing) O(n²) O(n²)
HashMap + Index Bounds O(n) O(n)
Recursion with Stop Value O(n) O(h)

Common Pitfalls

  • Building the right subtree before the left in the pointer-based approaches — preIdx then hands the left subtree's root to the right side.
  • Off-by-one in slicing: the left subtree has mid nodes, so its pre-order slice is [1, mid + 1), not [1, mid).
  • Relying on a map when values could repeat — this problem guarantees uniqueness; with duplicates the tree is not uniquely determined.
  • Making preIdx a local int parameter — Java passes it by value, so increments in the left call are lost to the right call. Use a field (or an array/holder).