Construct BST from Preorder Traversal
Build the BST matching the given preorder sequence (LeetCode 1008).
Open on LeetCode ↗Intuition
Same bounds trick as the GFG version: recurse with an upper bound only — a preorder value less than the bound extends the left side; once a value exceeds it, it belongs to an ancestor's right. One shared index, linear time.
Pre-order gives you the root first, and the BST property tells you where each subsequent value belongs — so one left-to-right pass with an upper bound rebuilds the tree. The bound is the whole idea: a value larger than the current limit cannot belong in this subtree, so the recursion returns and lets an ancestor claim it.
Approach
Upper bound suffices
build(bound): while the next key < bound, it's in this subtree. Left recursion bounds by the node's value, right by the inherited bound.
Stack alternative
Iterate keys; pop stack nodes smaller than the key (finding the parent), attach right, else attach left — same O(n).
Why linear
Every key is examined a constant number of times against bounds.
Solution & live demo
Common pitfalls
Searching for the split point each time
i = next(k for k, v in enumerate(preorder) if v > root_val) left = build(preorder[1:i]); right = build(preorder[i:])
def build(bound):
if self.i == len(preorder) or preorder[self.i] > bound:
return NoneScanning for the boundary and slicing costs O(n²) time and O(n²) memory in copies. The bound parameter decides membership in O(1), so the whole build is a single linear pass.
Passing the wrong bound to the right child
node.left = build(node.val) node.right = build(node.val)
node.left = build(node.val) node.right = build(bound)
The right subtree is capped by whatever limited this node, not by this node's value — values there are larger than node.val by definition. Reusing node.val rejects every legitimate right child and produces a left-only chain.
Using a local index instead of a shared cursor
def build(i, bound):
...
node.left = build(i + 1, node.val)self.i = 0 # build() advances self.i as it consumes
The right subtree must start wherever the left subtree stopped, and a local index can't know that without returning it. A shared cursor advances as a side effect, so each call naturally resumes where the previous one finished.
Edge cases
Pure left chain; every key admitted under successive tighter bounds.
Root only.