In a binary search tree, why must the first node whose key sits between two target keys be their lowest common ancestor?
answer
- compare both targets against one node
- when do both keys route the same way?
- the skipped subtree contains neither target
- the split point is the deepest shared node
- cost follows height, not node count
basics
~20 sIn a binary search tree, two keys stay in the same subtree only while both compare the same way against the current node. The first node that splits them is the deepest node holding both — their lowest common ancestor.
solid answer
~50 sStart at the root and compare both target keys with the current node's key. While both are smaller you move left, while both are larger you move right — and in each case the subtree you skipped provably contains neither target, so nothing you discarded could have been a common ancestor. The moment one key falls to the left and the other to the right (or one key equals the current node), that node separates them: it contains both, and no child of it does. That is exactly the lowest common ancestor. The walk is iterative, `O(h)` time in the tree's height and `O(1)` extra space. It rests entirely on the ordering invariant — on a binary tree with no key order a comparison tells you nothing about where a target lives, and this shortcut disappears.
code
pseudocode · 9 linesnode = root
while node != null:
if a < node.key and b < node.key:
node = node.left
else if a > node.key and b > node.key:
node = node.right
else:
return node // a and b straddle node, or one equals it
return null // walked off the tree: a target is absentgo deeper
Be ready to walk the descent out loud on a small drawn tree and say why the skipped side can be ignored. Naming the stopping condition — the two keys straddle the current key — is most of the answer.
Explain the invariant that licenses skipping a subtree, and give the honest cost as height-dependent. Handle the case where one target is the ancestor of the other without flinching.
Show what you do when a target may be missing: the descent still returns a node, and trusting it silently is a real defect. Say how you would verify presence in the same pass.
Frame it as a dependency on an invariant someone else must maintain. If the tree can lose its ordering or its balance guarantee, the shortcut's cost and correctness both change, and that belongs in the interface contract, not in tribal knowledge.
## What the question is really about The lowest common ancestor (LCA) of two nodes in a rooted tree is the deepest node that has both of them in its subtree, counting a node as an ancestor of itself. That definition works on *any* rooted tree. What makes a **binary search tree** special is not the definition but the shortcut: ordering lets you find the LCA by descending once from the root, comparing keys, without ever searching a subtree you do not enter. A concrete setting: a catalogue service keeps its category IDs in a search tree used as an index. Two IDs arrive, and you want the smallest indexed subtree that contains both — the node you can hand a range scan so it never touches keys outside the pair's span. That node is the LCA of the two keys, and it is often called the **split node** for exactly this reason. ## The ordering invariant In a binary search tree, for every node `v`: every key in `v`'s left subtree is smaller than `v.key`, and every key in `v`'s right subtree is larger. That single property is what turns a comparison into a routing decision. If a target key `a` satisfies `a < v.key`, then `a` cannot be anywhere in `v`'s right subtree — not because you looked, but because the invariant forbids it. ## The argument, step by step Stand at some node `v` that is known to contain both targets `a` and `b` in its subtree (true at the root, assuming both are present). - If `a < v.key` **and** `b < v.key`, both must live in the left subtree. So the left child also contains both, and it is deeper. `v` is therefore not the *lowest* common ancestor — descend left. - Symmetrically, if both keys exceed `v.key`, descend right. - Otherwise the keys straddle `v.key` (one below, one above), or one of them equals `v.key`. Now no single child of `v` can hold both: one target sits on the left side, the other on the right (or is `v` itself). `v` contains both and no descendant does, so `v` is the LCA. Each loop iteration either descends one level or terminates, so the loop runs at most `h + 1` times where `h` is the height. It keeps one cursor, so extra space is `O(1)`. ## Costs, stated precisely The cost is `O(h)`, not `O(log n)`. Those coincide **only when the tree is balanced**. A search tree built by inserting already-sorted IDs degenerates into a chain, and then `h = n - 1` and this descent is `O(n)` — the same order as searching an unordered tree. "Search tree" is a shape claim about ordering, never a promise about height; only a self-balancing variant makes the `O(log n)` claim honest. ## The boundary cases interviewers probe **One target is an ancestor of the other.** If `a` sits above `b`, the descent reaches the node holding `a` and stops there, because `a == v.key` no longer routes in a single direction. The answer is `a` itself — correct, because a node is its own ancestor. Candidates who define ancestry as *strictly* above get this wrong and start hunting for a parent. **A target is missing from the tree.** The loop still stops somewhere: at the deepest node whose key lies between the two search keys, or it runs off the bottom and finds nothing. That stopping node is the split point of the two *search paths*, which is a meaningful object for a range scan, but it is not the LCA of two existing nodes. If your caller needs the guarantee that both nodes exist, verify presence — you can do it during the same descent by remembering whether each key was matched. **Duplicate keys.** If the tree admits duplicates, "the node with key `a`" is ambiguous and so is its ancestor. Pin down the duplicate policy before claiming the shortcut applies. ## Why it evaporates without ordering On a binary tree with no key order, comparing a target key to `v.key` yields no information about which side holds the target, so no subtree can be skipped. You are forced into a full traversal, and the LCA is found by a different technique entirely: recurse into both children and look for the node where the two targets surface from different sides. That is `O(n)`, and it is the price of losing the invariant — which is the real lesson of this question. The shortcut is not a property of trees; it is a property of *ordered* trees, and it is worth exactly as much as the invariant you can prove still holds.
- What does the descent return if one of the two target keys is not in the tree?It still stops at the deepest node whose key lies between the two search keys, or it walks off the bottom. That node is the split point of the two search paths, not the ancestor of two real nodes. If the caller needs both nodes to exist, check for a key match during the same descent and report the miss rather than returning a confident wrong node.
- Why doesn't this comparison work on a binary tree with no key ordering?Without the ordering invariant a smaller key can sit anywhere, so comparing it to the current node's key tells you nothing about which child to enter. No subtree can be ruled out, so you must explore both sides — an `O(n)` traversal that identifies the node where the two targets surface from different subtrees.
- How does an unbalanced tree change the cost of this descent?It is `O(h)`, and `h` is `O(log n)` only under a balancing guarantee. Inserting keys in sorted order builds a chain with `h = n - 1`, and the descent becomes `O(n)`. Being a search tree constrains ordering, not height — the logarithmic claim belongs to self-balancing variants.
Two people follow the same road out of town and only part ways at a fork; the fork is the last place they were still together.
saying these in an interview costs you the question
- Claims the same key-comparison descent works on any binary tree
- States the cost as O(log n) without a balance assumption
- Searches both subtrees anyway, discarding the ordering
- Denies that a node can be its own ancestor
- Assumes the answer must be the root or a leaf