Kth Smallest Element in a BST looks like a tree problem, but it is really an ordering problem in disguise. The trick is knowing one fact about binary search trees: an in-order traversal hands you the values already sorted.
Problem. Given the root of a binary search tree and an integer k, return the k-th smallest
value in the tree (1-indexed).
Example: the tree with root 5 (children 3 and 6; 3 has children 2 and 4; 2 has child 1)
and k = 3 → answer 4. The sorted values are 1, 2, 3, 4, 5, 6, and the 3rd is 4.
The slow way first
The brute-force approach: traverse the whole tree, collect every value into a list, sort the list, and return list[k - 1]. That works, but it visits all n nodes and then sorts — O(n log n) time and O(n) space, even when k is tiny.
The question to ask: do I actually need every value? No — I only need the first k in sorted order. If I can produce values in sorted order one at a time, I can stop the moment I have produced k of them.
The idea: in-order visits a BST in sorted order
In a BST, every value in the left subtree is smaller than the node, and every value in the right subtree is larger. So an in-order traversal — visit left subtree, then the node, then right subtree — emits values from smallest to largest. The k-th value it emits is the k-th smallest.
To stop early we run the traversal iteratively with an explicit stack: dive left as far as we can (pushing every node), pop the deepest node (the next smallest), count it, and only then turn to its right subtree.
The key insight: we never need to visit the whole tree. The instant count reaches k, the node we just popped is the answer and we return.
Walk through it
Step through the animation. We push 5, 3, 2, 1 going left, then pop them back. Popping 1 makes count 1; popping 2 makes count 2 and queues its right child 4; popping 4 makes count 3 == k, so we return 4 and stop — nodes 5 and 6 are never even touched.
Pseudocode
stack = empty, count = 0, node = root
while node is not null OR stack is not empty:
while node is not null: # go as far left as possible
push node, node = node.left
node = pop stack # the next-smallest unvisited node
count = count + 1
if count == k:
return node.value # found it, stop early
node = node.right # now explore its right subtreeThe Python solution
def kth_smallest(root, k):
stack, count = [], 0
node = root
while node or stack:
while node: # go as far left as possible
stack.append(node)
node = node.left
node = stack.pop() # smallest unvisited node
count += 1
if count == k:
return node.val
node = node.right # then explore the right subtree
return -1- The inner
while node:loop walks down the left spine, stacking nodes so we remember where to return. stack.pop()always gives the smallest unvisited node, because the left-most node is on top.count += 1thenif count == kis the early stop — we return the moment we have emittedkvalues.node = node.rightis what makes this in-order: after a node, we explore its right subtree before backing up further.
Complexity
| Case | Time | Notes |
|---|---|---|
| Collect all + sort | O(n log n) (moderate) | visits every node, then sorts |
| Iterative in-order (this) | O(h + k) (moderate) | h to reach the smallest, then k pops |
O(h) (moderate)We descend the height h of the tree to reach the smallest value, then pop k times — O(h + k), far less than the whole tree when k is small. Space is O(h) for the stack (the left spine on it at most).
When this pattern shows up
Whenever a problem mentions a BST and order — kth smallest/largest, range sums, the closest value, validating sorted-ness — think in-order traversal. Doing it iteratively with a stack lets you stop early and keeps recursion depth off the call stack.
The "sorted order" guarantee only holds for a valid BST. On a plain binary tree (no ordering invariant), in-order does not give sorted values, and this approach is wrong.
Practice
For the example tree with k = 3, which nodes does the algorithm never visit, and why?
1. Why does an in-order traversal of a BST produce sorted values?
2. What is the time complexity of the iterative in-order solution?
3. What does the explicit stack hold at any moment?
4. When can we stop and return early?