Binary Trees · 20 of 35
Construct Binary tree from Inorder and preorder traversal
Rebuild a tree from two lists of its nodes: one that names each parent before its children, and one that reads the tree from left to right.
- Simple way
- time O(n^2)
room O(n) - Clever way
- time O(n)
room O(n)
The problem, simply
You get two lists of the same tree's values. All values are different.
preorderlists a node first, then everything in its left subtree, then everything in its right subtree.inorderlists everything in the left subtree, then the node, then everything in the right subtree. It is the tree read from left to right.
Build the tree and give back its root.
A story to remember it
Picture it
The tree we want to rebuild, and its two lists. Preorder starts with the root 1. In inorder, 1 has 4, 2, 7, 5 on its left and 3, 6 on its right.
- answer
Examples
Seven nodes
- In
preorder = [1, 2, 4, 5, 7, 3, 6], inorder = [4, 2, 7, 5, 1, 3, 6]- Out
[1, 2, 3, 4, 5, null, 6, null, null, 7]
1 is the root. 4, 2, 7, 5 build its left side and 3, 6 build its right side.
The classic one
- In
preorder = [3, 9, 20, 15, 7], inorder = [9, 3, 15, 20, 7]- Out
[3, 9, 20, null, null, 15, 7]
3 is the root. Only 9 is on its left. 15, 20, 7 are on its right, with 20 as their root.
A left leaning chain
- In
preorder = [1, 2, 3], inorder = [3, 2, 1]- Out
[1, 2, null, 3]
Every node has everything else on its left, so each one is the left child of the one before.
One node
- In
preorder = [5], inorder = [5]- Out
[5]
The root alone.
Empty lists
- In
preorder = [], inorder = []- Out
[]
No nodes, so return null.
Way 1: the simple way
Use the roll call idea directly. Walk through preorder one card at a time. Each card is the root of the window it lands in. Find it in inorder by looking at every card in the window.
- Keep a finger
ponpreorder. Start with the wholeinorderlist as the window. - The card at
pis the root of the window. Movepforward. - Search the window in
inorderfor that card. Call its positionk. - Build the left child from the window left of
k, then the right child from the window right ofk. The left side must be built first, because preorder lists it first.
class Solution {
private int p;
public TreeNode buildTree(int[] preorder, int[] inorder) {
p = 0;
return build(preorder, inorder, 0, inorder.length - 1);
}
private TreeNode build(int[] pre, int[] in, int lo, int hi) {
if (lo > hi) return null; // empty window, no node
TreeNode root = new TreeNode(pre[p++]);
int k = lo;
while (in[k] != root.val) k++; // search the window
root.left = build(pre, in, lo, k - 1);
root.right = build(pre, in, k + 1, hi);
return root;
}
}How long it takes: each node may search a window as long as the whole list. For a stick shaped tree that adds up to O(n^2). Extra room: the waiting helpers, up to O(n) deep.
Way 2: the clever way
The search is the slow part. Before we start, write down where every value sits in inorder, in a map. Then finding k is one quick lookup.
- Fill a map from value to its index in
inorder. - Build exactly as before, but get
kfrom the map.
Roots come from preorder, sides come from inorder
01 / 09
The first card in preorder is always the root of the whole tree. In inorder, the root splits the cards: the left part is its left subtree, the right part is its right subtree.
- looking now
- done
- answer
- just added
import java.util.*;
class Solution {
private int p;
private Map<Integer, Integer> where = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
p = 0;
where.clear();
for (int i = 0; i < inorder.length; i++) where.put(inorder[i], i);
return build(preorder, 0, inorder.length - 1);
}
private TreeNode build(int[] pre, int lo, int hi) {
if (lo > hi) return null;
TreeNode root = new TreeNode(pre[p++]); // next roll call name is the root
int k = where.get(root.val); // where it stands in the photo
root.left = build(pre, lo, k - 1); // left group first
root.right = build(pre, k + 1, hi);
return root;
}
}How long it takes: one quick lookup per node, O(n). Extra room: the map plus the waiting helpers, O(n).
Watch out for
- Repeated values break the idea. If two nodes hold the same value, you cannot tell which one the map means, and many trees can fit the lists.
- Forgetting to reset
pand the map between calls when they are fields. - Copying sub arrays with
Arrays.copyOfRangeat every step. It works, but it costsO(n^2)time and room. Pass window bounds instead.
What interviewers ask next
- Inorder and postorder instead? Postorder ends with the root. Walk it from the back, and build the right side before the left side. That is LeetCode 106.
- Preorder and postorder? Not enough in general. A node with one child could have it on the left or on the right, and both lists look the same. If every node has 0 or 2 children, it works (LeetCode 889).
- A binary search tree from preorder alone? Yes. Inorder of a search tree is just the sorted values, or use bounds and build in
O(n)(LeetCode 1008). - Can you do it without the map and without recursion? Yes, with a stack and two fingers, one on each list. It is a nice
O(n)trick but harder to explain on a whiteboard.
Remember this
Grown-up words: the roll call is the preorder traversal, the class photo is the inorder traversal, the groups are subtrees, the photo window is an index range, and splitting the job into two smaller jobs is divide and conquer.