Lowest Common Ancestor of a Binary Search Tree
You are given the root of a binary search tree (every value in a node's left subtree is smaller than the node, every value in its right subtree is larger) and two different nodes p and q that both belong to the tree.
Return their lowest common ancestor: the deepest node that has both p and q in its subtree. A node counts as part of its own subtree, so if p is an ancestor of q, the answer is p itself.
Trees are written in level order: the root first, then each level from left to right, with null marking a missing child. For example [4,2,null,1] is a root 4 whose left child 2 has a left child 1.
In the examples p and q are written as values; your function receives the actual nodes with those values, and the judge checks the value of the node you return.
Example 1
Example 2
Example 3
Constraints
2 <= number of nodes <= 104-109 <= Node.val <= 109- All values are distinct, and the tree is a valid binary search tree.
p != q, and both are nodes of the tree.
Pattern Path · Binary Search Trees · problem 99 of 169
Start simple
Record the root-to-node path for p and for q (ignoring the ordering), then return the last node the two paths share: O(n) time and O(n) space.
The key idea
The ordering of a binary search tree tells you, at every node, which subtree a value must be in. Use it to follow the path from the root toward both targets at once.
- If
pandqare both smaller than the current node, both are in the left subtree, so their lowest common ancestor is too: move left. - If both are larger, move right for the same reason.
- Otherwise the paths split here: one target is on the left and the other on the right, or the current node is one of them. No deeper node can contain both, while this node does, so it is the answer.
This never examines more than one root-to-leaf path, so it runs in time proportional to the tree's height: O(log n) for a balanced tree and O(n) in the worst case. Written as a loop it needs only constant extra space. A general binary tree has no ordering to guide you, which is why this version is easier than the general one.
Complexity
- Time:
O(h) - Space:
O(1)
Python
class Solution:
def lowestCommonAncestor(self, root, p, q):
node = root
while node:
if p.val < node.val and q.val < node.val:
node = node.left # both targets are in the left subtree
elif p.val > node.val and q.val > node.val:
node = node.right # both targets are in the right subtree
else:
return node # the targets split here, or one of them is this node
return None
JavaScript
var lowestCommonAncestor = function(root, p, q) {
let node = root;
while (node) {
if (p.val < node.val && q.val < node.val) {
node = node.left; // both targets are in the left subtree
} else if (p.val > node.val && q.val > node.val) {
node = node.right; // both targets are in the right subtree
} else {
return node; // the targets split here, or one of them is this node
}
}
return null;
};
What the interviewer is checking
The interviewer checks whether you exploit the BST ordering to walk a single path instead of using the general tree algorithm, and whether you handle the case where one node is the ancestor of the other.
Mistakes to avoid
- Ignoring the BST property and searching both subtrees like in a general tree, which works but misses the point.
- Forgetting that a node can be its own ancestor, and continuing past p when q is below it.
- Comparing nodes instead of their values, or assuming p.val is smaller than q.val.
Follow-ups to expect
- What if the tree is an ordinary binary tree? (Post-order search returning found nodes.)
- What if p or q might be missing from the tree? (Verify both exist first.)
- What if nodes have parent pointers? (Intersect the two upward paths.)
In real software
Finding the narrowest common range covering two keys in an ordered index, or the most specific shared category in a sorted hierarchy, follows the same split-point walk.