Binary Search Trees · 7 of 22
Find LCA of 2 nodes in a BST
Find the lowest spot in a sorted tree that is an ancestor of two given numbers, by walking down until the two numbers want to go different ways.
- Simple way
- time O(n)
room O(h) - Clever way
- time O(h)
room O(1)
The problem, simply
You get a binary search tree (BST) and two numbers p and q that are both in it. Find their lowest common ancestor (LCA): the deepest spot that has both p and q somewhere below it. A spot counts as being below itself, so if p sits above q, the answer is p.
A story to remember it
Picture it
The paths from the top to 3 and to 5 share 6, 2 and 4, then split at 4. So the answer for 3 and 5 is 4.
- checking
- answer
- path
Examples
They split low in the tree
- In
[6, 2, 8, 0, 4, 7, 9, null, null, 3, 5], p = 3, q = 5- Out
4
Both go left at 6, both go right at 2, and at 4 one goes left and one goes right.
They split at the top
- In
same tree, p = 2, q = 8- Out
6
At 6, 2 wants left and 8 wants right. They split right away.
One is above the other
- In
same tree, p = 2, q = 5- Out
2
At 6 both go left. At 2, p is the spot itself. A spot is its own ancestor, so 2 is the answer.
Same number twice
- In
same tree, p = 7, q = 7- Out
7
The walk stops at 7 because neither "both smaller" nor "both bigger" is true there.
Way 1: the simple way
Forget the sorting and solve it for any binary tree. Ask each side: "do you contain p or q?"
- If the spot is
null, returnnull. - If the spot is
porq, return it. - Ask the left side and the right side.
- If both sides found something, this spot is where they split. Return it.
- Otherwise return whichever side found something.
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) return root; // one on each side
return left != null ? left : right; // pass up what was found
}
}How long it takes: it may visit every spot, O(n). Extra room: the recursion depth, O(h). Correct, but it ignores the signposts.
Way 2: the clever way
Walk down with one finger, curr, starting at the top.
- If both
pandqare smaller thancurr, both live on the left. Go left. - If both are bigger, both live on the right. Go right.
- Otherwise they split here, or one of them is
curr. Returncurr.
Why it is the lowest: at the split, one number is on the left side and the other on the right (or is curr itself). No spot below curr can have both, because the two sides never meet again.
Walk together until the friends split
01 / 06
Looking for the split of 3 and 5. At 6, both are smaller. Go left together.
- p
- 3
- q
- 5
- looking now
- checking
- seen
- answer
- path
- ignored
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
TreeNode curr = root;
while (curr != null) {
if (p.val < curr.val && q.val < curr.val) {
curr = curr.left; // both live on the left
} else if (p.val > curr.val && q.val > curr.val) {
curr = curr.right; // both live on the right
} else {
return curr; // they split here
}
}
return null; // only if p or q is missing
}
}How long it takes: one road down, O(h). Extra room: one finger, O(1).
Watch out for
- If
porqmight be missing from the tree, the walk still returns a spot. Check both are really there (two searches) before trusting the answer. - Comparing node objects in Way 2. Compare values, since the walk only needs the numbers.
- Using Way 2 on a tree that is not a BST. It only works because of the ordering.
What interviewers ask next
- LCA in a plain binary tree (LeetCode 236). Use Way 1. It is the general tool.
- Distance between
pandqin a BST. Find the split spot, then add the number of steps from it down topand down toq. - Many LCA questions on a fixed tree. Precompute "jump 1, 2, 4, 8 ... steps up" tables (binary lifting) for
O(log n)per question. - What if nodes have parent pointers? Walk up from both, like finding where two linked lists meet.
Remember this
Grown-up words: the last corner the friends shared is the lowest common ancestor, the corner where they split is the split point of the two search paths, and "a spot is below itself" means a node is a descendant of itself.