Given an integer array preorder — the preorder traversal of a binary search tree with distinct values — construct the BST and return its root.
The tree is returned in level-order (breadth-first), using null for missing children.
Input: preorder = [8, 5, 1, 7, 10, 12] Output: [8, 5, 10, 1, 7, null, 12] Root 8; 5 and 10 are its children; 1, 7 under 5; 12 under 10.
Input: preorder = [1, 3] Output: [1, null, 3] 3 > 1, so it's the right child.
- 1 <= preorder.length <= 100 - 1 <= preorder[i] <= 10^8 - All values are unique - preorder is a valid preorder of a BST
A BST is special: preorder alone determines it (no inorder needed), because the ordering tells you where each value goes. The simplest build inserts each value into the BST in order. The slick O(n) build uses a monotonic stack that tracks the chain of ancestors a new value can attach under.
“Why is preorder enough for a BST?”
The ordering acts as the second traversal — you always know which side a value belongs on.
“Values distinct?”
Yes.
For a BST, preorder alone is enough because the ordering tells me left vs right, so I can insert each value in turn.
For O(n) I keep a stack of ancestors: a smaller value is the left child of the top, a larger value pops until it finds the parent whose right child it becomes.
Worked example — preorder = [8, 5, 1, 7, 10, 12]
8 root. 5<8 -> left of 8. 1<5 -> left of 5.
7>1,7>5 pop 1,5 -> right of 5. 10>7,>8 pop 7,8 -> right of 8. 12>10 -> right of 10.
8
/ \
5 10
/ \ \
1 7 12
The ordering replaces the need for inorder — the first value is the root and comparisons place the rest.
The monotonic stack holds the ancestors a new value could attach under.
That's what makes the stack build O(n).
| Insert each value | Monotonic stack | |
|---|---|---|
| Idea | BST-insert values one by one | Attach via a stack of ancestors |
| Time | O(n * height) | O(n) |
| Space | O(height) | O(n) |
Both build the same BST; the stack version is linear. Full code is in the Approaches selector below.
Key takeaway
Preorder alone builds a BST. Insert each value (O(n·h)), or use a monotonic stack — smaller ⇒ left child of the top, larger ⇒ pop to the parent and become its right child (O(n)).
for v after the root:
if v < top: top.left = v
else: pop while top < v; last_popped.right = v
push v