Back to Trees & BST
Q23Question 23 of 25

Construct Tree from Preorder and Inorder Traversal

Key Concepts
  • Preorder gives the next root (first element); inorder splits it into left and right subtrees
  • A HashMap from value to inorder index makes root lookup O(1) instead of O(n) per node
  • A single forward-moving pointer into the preorder array supplies each root in order
  • You must build the left subtree before the right to consume preorder values correctly
  • Time is O(n) with the map; without it, linear scans make the algorithm O(n^2)
  • This reconstruction requires unique values; duplicates make the inorder split ambiguous

Definition

Preorder gives the next root, inorder splits that root into left and right subtrees, and recursion rebuilds the whole tree.
  • Preorder visits node, left, right, so the first element is always the root of the current subtree.
  • Inorder visits left, node, right, so the root's position splits the array into left and right subtree values.
  • HashMap maps each value to its inorder index for O(1) root lookup.
  • Preorder pointer moves forward, supplying each root in exactly the order needed.
  • Build order requires left subtree first, then right, to match preorder's node-left-right sequence.
  • Time is O(n) with the map; space is O(n) for the map and recursion.

Rajesh has two records of the National Bank of India's org chart taken in two different reading orders. The preorder record always lists a manager before their teams, so the very first name is the top manager. The inorder record lists the left team, then the manager, then the right team. Once Rajesh finds that top manager's name in the inorder record, everyone to the left is the left team and everyone to the right is the right team. He repeats this for each team to rebuild the whole chart.

Understanding the Concepts

What is the Construct Tree from Preorder and Inorder problem?

Given two arrays representing the preorder and inorder traversal of a binary tree with unique values, reconstruct and return the original tree. This problem tests understanding of how traversal orders encode tree structure and how to use that encoding to rebuild the tree.

JAVA
package com.bank.service;

import java.util.HashMap;
import java.util.Map;

public class HierarchyRebuilder {
    private int preorderIndex = 0;
    private Map<Integer, Integer> inorderMap = new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        for (int i = 0; i < inorder.length; i++) {
            inorderMap.put(inorder[i], i);
        }
        return build(preorder, 0, inorder.length - 1);
    }

    private TreeNode build(int[] preorder, int inLeft, int inRight) {
        if (inLeft > inRight) return null;
        int rootVal = preorder[preorderIndex++];
        TreeNode root = new TreeNode(rootVal);
        int mid = inorderMap.get(rootVal);
        root.left = build(preorder, inLeft, mid - 1);
        root.right = build(preorder, mid + 1, inRight);
        return root;
    }
}

Why does preorder plus inorder uniquely define a tree?

Preorder visits node-left-right, so the first element is always the root of the current subtree. Inorder visits left-node-right, so finding the root in the inorder array splits it into two halves: everything before the root belongs to the left subtree, and everything after belongs to the right subtree. This split is unambiguous when values are unique.

TEXT
Preorder: [3, 9, 20, 15, 7]
Inorder:  [9, 3, 15, 20, 7]

Root = 3 (first in preorder)
Inorder split: [9] | 3 | [15, 20, 7]
Left subtree values: [9]
Right subtree values: [15, 20, 7]

Next root from preorder: 9 (for left subtree)
Next root from preorder: 20 (for right subtree)

Why is the HashMap critical for performance?

Without the map, finding the root's position in the inorder array requires a linear scan, making the algorithm O(n^2) in the worst case. With the map, each lookup is O(1), and since each node is created exactly once, the total time is O(n).

JAVA
// Without map: O(n) scan per node → O(n^2) total
for (int i = inLeft; i <= inRight; i++) {
    if (inorder[i] == rootVal) { mid = i; break; }
}

// With map: O(1) lookup per node → O(n) total
int mid = inorderMap.get(rootVal);

Why must you build left before right?

Preorder visits node, then left subtree, then right subtree. The preorder pointer moves forward as each root is consumed. If you build the right subtree first, it would consume values meant for the left subtree, corrupting the tree. The order must match the preorder traversal order.

JAVA
// CORRECT: left first, then right
root.left = build(preorder, inLeft, mid - 1);   // consumes left's preorder values
root.right = build(preorder, mid + 1, inRight);  // consumes right's preorder values

// WRONG: right first, then left
root.right = build(preorder, mid + 1, inRight);  // steals left's values!
root.left = build(preorder, inLeft, mid - 1);    // gets wrong values

How does the base case work?

When inLeft > inRight, the inorder range is empty, meaning there are no nodes in this subtree. This is the signal to return null. It handles both empty subtrees and the leaf termination correctly.

JAVA
if (inLeft > inRight) return null;

What about postorder and inorder reconstruction?

Postorder visits left, right, then node, so the last element is the root. You read postorder from right to left and must build the right subtree before the left to match the reverse order.

| Aspect | Preorder + Inorder | Postorder + Inorder |
|--------|-------------------|--------------------|
| Root location | First in preorder | Last in postorder |
| Pointer direction | Left to right | Right to left |
| Build order | Left then right | Right then left |

What are edge cases?

  • Empty arrays: return null.
  • Single element: return a leaf node.
  • Skewed tree (all left or all right): one side of every split is always empty.
  • The preorder and inorder arrays must represent the same tree; if they do not, the result is undefined.
JAVA
// Edge case: single node
// Preorder: [1], Inorder: [1]
// Root = 1, no left or right subtree
// Result: a single leaf node with value 1

What are common mistakes?

The first mistake is forgetting to use a class-level preorder pointer and instead passing index ranges for both arrays, which complicates the logic. The second mistake is building right before left, which corrupts the preorder consumption order. The third mistake is searching linearly in the inorder array instead of using a map.

JAVA
// WRONG: linear search without map
int mid = -1;
for (int i = inLeft; i <= inRight; i++) {
    if (inorder[i] == rootVal) { mid = i; break; }
}
// This works but is O(n^2) in the worst case

// CORRECT: use the precomputed map
int mid = inorderMap.get(rootVal);

What about duplicate values?

If the tree has duplicate values, the root's position in the inorder array is ambiguous because the same value appears multiple times. You cannot uniquely determine which occurrence is the root, so the tree cannot be uniquely reconstructed. The algorithm assumes unique values.

What should a senior engineer know?

At the National Bank of India, Rajesh used this to migrate an org hierarchy that a legacy system exported only as two separate traversal logs. The service rebuilt the actual tree from the preorder and inorder logs so it could be loaded into the new system. The HashMap kept the rebuild fast even for hierarchies with thousands of employees, and a validation step confirmed the rebuilt tree's traversals matched the originals.

Visual Overview

DIAGRAM
  Reconstruction from preorder and inorder
  ==========================================

  Preorder: [3, 9, 20, 15, 7]    (read left-to-right)
             ^  pointer moves →

  Inorder:  [9, 3, 15, 20, 7]
                 ^
  Step 1: root = 3, split inorder at 3
           left: [9]    right: [15, 20, 7]

  Step 2: root = 9 (next preorder), split: [] | 9 | []
           leaf node

  Step 3: root = 20 (next preorder), split at 20
           left: [15]   right: [7]

  Step 4: root = 15, leaf
  Step 5: root = 7, leaf

  Rebuilt tree:
         3
        / \
       9   20
          /  \
         15    7

  Inorder map:  {9:0, 3:1, 15:2, 20:3, 7:4}

Key Takeaway

Reconstructing a binary tree from its preorder and inorder traversals rests on two facts that fit together perfectly. Preorder visits node then left then right, so reading preorder from the front always gives the next root. Inorder visits left then node then right, so finding the root in the inorder array splits it cleanly into the left subtree before it and the right subtree after it.

The implementation keeps a single forward-moving pointer into the preorder array to supply each root, and a precomputed HashMap from value to inorder index for O(1) root lookup. You recurse by passing the current inorder range, creating a node from the next preorder value, looking up its split point, and building the left subtree before the right. The order is critical: building left first matches the preorder consumption sequence, and swapping them corrupts the tree.

Without the HashMap, each root lookup is a linear scan and the algorithm degrades to O(n^2). With the map, it is O(n) overall. The algorithm also requires unique values because duplicates make the inorder split ambiguous.

At the National Bank of India, Rajesh used this to migrate an org hierarchy from a legacy system that had exported the structure only as two traversal logs. The service rebuilt the actual tree from the logs and validated the result by re-traversing and comparing, and the HashMap kept the rebuild fast even for large hierarchies with thousands of employees.

Remember one sentence: preorder gives the root, inorder gives the split, the HashMap makes it linear, and you must build left before right.

---

Share
Use ← → arrow keys to navigate