Convert Sorted Array to BST
Given an integer array nums sorted in strictly increasing order, build a height-balanced binary search tree containing exactly those values, and return its root. Binary search tree means every node's value is greater than all values in its left subtree and smaller than all values in its right subtree. Height-balanced means that at every node the two subtree heights differ by at most 1. Several valid trees usually exist; any one of them is accepted.
- 1 <= nums.length <= 10⁴
- -10⁴ <= nums[i] <= 10⁴
- nums is sorted in strictly increasing order, so there are no duplicates
- Any height-balanced BST over these values is accepted
nums = [-10,-3,0,5,9][0,-3,9,-10,null,5]nums = [1,3][3,1]nums = [0][0]nums = [-10,-3,0,5,9,12,20][5,-3,12,-10,0,9,20]Two demands at once: the tree must be a binary search tree (every node bigger than all of its left subtree, smaller than all of its right) and it must be height-balanced (at every node the two sides' heights differ by at most 1, so the tree stays shallow — about log₂N tall).
Why balance matters: the lazy "insert values one by one" gives a legal BST that's useless.
insert -10, -3, 0, 5, 9 in order:
-10
\
-3
\
0 each value is bigger than all before it,
\ so it keeps hanging off the right ->
5 a chain of height 5. Search costs N, not log N.
\
9Read any BST left → node → right (that's in-order) and the values come out sorted — everything smaller than a node before it, everything larger after. So the array we're handed is the in-order reading of the tree we must build. The order of values is fixed; our only freedom is which value tops each range — and that single choice decides the height.
Choose a root. Everything before it in the array must go left, everything after must go right — the BST rule leaves no choice. So the split sizes depend only on where you pick:
nums = [ -10 -3 0 5 9 ]
^ pick MIDDLE as root
left = [-10 -3] right = [5 9] halves -> sizes differ by <= 1Pick the first value instead and the left gets nothing, the right gets everything — the chain again. Pick the middle and both sides are as equal as possible. Recurse the same way on each half and no node can come out lopsided; the range halves every level, so the height is about log₂N.
def build(lo, hi): # inclusive index range
if lo > hi:
return None # empty range: no subtree here
mid = (lo + hi) // 2 # the middle value becomes this subtree's root
node = Node(nums[mid])
node.left = build(lo, mid - 1) # strictly smaller values
node.right = build(mid + 1, hi) # strictly larger values
return node
return build(0, len(nums) - 1)lo > hi, not lo == hi. A range with one value is still a real subtree that must produce a leaf; only a crossed range (indices passed each other) is empty and returns null. And the halves use mid - 1 / mid + 1, never mid — the middle value is already this node, so neither side may include it again (pass mid and a one-element range recurses forever). When a range has an even count there's no exact middle; (lo + hi)//2 takes the lower one, and taking the upper is equally valid — just a different accepted tree.nums = [-10, -3, 0, 5, 9], picking the middle of each range:
[-10 -3 | 0 | 5 9] mid = 0 -> root 0
| left [-10 -3], right [5 9]
[-10 | -3] mid = -10 -> left empty, right = -3 (leaf)
[5 | 9] mid = 5 -> left empty, right = 9 (leaf)
result: 0
/ \
-10 5
\ \
-3 9Every node's two sides differ in height by at most 1, and reading it in-order gives back -10, -3, 0, 5, 9. O(N) time (one node per value), O(log N) recursion depth.
Two takeaways. In-order is the traversal that exposes a BST's sorted order — validating a BST, finding its k-th smallest, or flattening it back to a list are all in-order walks. And when you're handed sorted data and asked for a balanced structure, the middle element is almost always the root — the same halving instinct behind binary search and merge sort, used any time a structure's cost depends on its depth.
Array to Balanced BST
Binary Split Strategy
Strategy
Focus on the recursive nature of trees: solve for subtrees and combine results at the root.
"Divide and Conquer: Subproblem → Recurrence → Result"