Rebuild a Search Tree From Its Node-First Listing
Solve this ProblemYou are given the pre-order listing of a binary search tree with distinct values: each node appears before its left subtree, which appears before its right subtree. Rebuild the tree and return its root. A binary search tree is fully determined by its pre-order listing.
You can insert the values one at a time into an empty tree, which works because of the order they are listed in. A single left-to-right pass that carries an upper bound for each subtree does the same in linear time.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
0 ≤ preorder.length ≤ 100; all values are distinct, 0 ≤ preorder[i] ≤ 1000 - ◆
preorder is the pre-order listing (node, left subtree, right subtree) of some binary search tree (left subtree smaller, right subtree larger); such a tree is guaranteed to exist - ◆
Return the root of that tree (checked as a level-order list); an empty listing gives the empty tree - ◆
A tree is uniquely determined by its pre-order listing together with the search-tree property
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Insert the Values One by One Into an Empty Tree
BruteThe pre-order listing is exactly a valid order in which to insert the values into an initially empty search tree: every node is listed before its descendants, so inserting in that order puts each value back below its old parent. Start with an empty tree and insert each value with the ordinary search-tree insertion (walk down comparing, attach as a new leaf). Every insertion costs the current height: O(n · h) time — O(n²) for a chain — and O(h) recursion space.
O(n · h)O(h)1class Solution {
2 public TreeNode bstFromPreorder(int[] preorder) {
3 TreeNode root = null;
4 for (int v : preorder) root = insertOne(root, v);
5 return root;
6 }
7
8 private TreeNode insertOne(TreeNode node, int v) {
9 if (node == null) return new TreeNode(v);
10 if (v < node.val) node.left = insertOne(node.left, v);
11 else node.right = insertOne(node.right, v);
12 return node;
13 }
14}Optimal — One Pass With an Upper Bound
OptimalRead the pre-order list once, from left to right, with a single running index. To build a subtree that may only contain values below some upper bound: if the next unread value is missing or is larger than the bound, this subtree is empty. Otherwise the next value is the subtree's root (consume it), its left subtree is built next with the root's value as the new bound (left values must be smaller), and after that its right subtree with the ORIGINAL bound (right values are larger than the root but must still respect the bound inherited from above). Every value is consumed exactly once: O(n) time, O(h) recursion space.
O(n)O(h)1class Solution {
2 private int idx;
3
4 public TreeNode bstFromPreorder(int[] preorder) {
5 idx = 0;
6 return build(preorder, Integer.MAX_VALUE);
7 }
8
9 private TreeNode build(int[] preorder, int bound) {
10 if (idx == preorder.length || preorder[idx] > bound) return null;
11 TreeNode node = new TreeNode(preorder[idx++]);
12 node.left = build(preorder, node.val);
13 node.right = build(preorder, bound);
14 return node;
15 }
16}