Binary Search Trees (BSTs) are special because they allow us to make decisions without exploring every node. This problem is a great example of taking advantage of that property to find the Lowest Common Ancestor (LCA) in O(h)time instead of searching the entire tree.
Problem
Given a Binary Search Tree and two nodes p and q, return their Lowest Common Ancestor (LCA).
The Lowest Common Ancestor is the lowest node in the tree that has both p and q as descendants.
A node is considered a descendant of itself, so if one of the nodes is an ancestor of the other, that node is the answer.
Example 1
5
/ \
3 8
/ \ / \
1 4 7 9
\
2
p = 3
q = 8
Answer = 5Since 3 is on the left of 5 and 8 is on the right, the first node where they split is 5.
Example 2
5
/ \
3 8
/ \
1 4
p = 3
q = 4
Answer = 3One node (3) is already an ancestor of the other (4), so the answer is simply 3.
Key Observation
Unlike a normal binary tree, a BST guarantees:
- Every value in the left subtree is smaller.
- Every value in the right subtree is larger.
This lets us determine which direction to move simply by comparing values.
At every node, only three situations are possible.
Case 1: Both nodes are smaller
10
/
5
p = 2
q = 7Both values are less than 10, so both nodes must be somewhere in the left subtree.
curr = curr.leftCase 2: Both nodes are larger
10
\
15
p = 12
q = 20Both values are greater than 10, so both nodes must be in the right subtree.
curr = curr.rightCase 3: The nodes split
10
/ \
5 15
p = 5
q = 15One node is on the left and one is on the right.
This means the current node is the first place where their paths diverge, making it the Lowest Common Ancestor.
The same logic also covers the situation where the current node is equal to either p or q.
10
/
5
\
7
p = 5
q = 7Since 5 is an ancestor of 7, the answer is 5.
Algorithm
Start from the root.
While the current node exists:
- If both
pandqare smaller than the current node, move left. - Else if both are larger than the current node, move right.
- Otherwise, you've found the Lowest Common Ancestor.
Because the BST tells us exactly which direction to move, we never need to search both subtrees.
Solution
# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
curr = root
while curr:
if p.val < curr.val and q.val < curr.val:
curr = curr.left
elif p.val > curr.val and q.val > curr.val:
curr = curr.right
else:
return currDry Run
Consider:
6
/ \
2 8
/ \ / \
0 4 7 9
/ \
3 5
p = 2
q = 8Step 1
Current node = 6
2 < 68 > 6
The nodes are on different sides.
So we've already found the split point.
Answer = 6Another example:
p = 2
q = 4Current = 6
Both are smaller.
Move left.
curr = 2Current = 2
One node is the current node itself.
We return 2.
Time Complexity
We only travel from the root down toward a leaf.
Time Complexity: O(h)
where h is the height of the tree.
- Balanced BST:
O(log n) - Worst-case (skewed BST):
O(n)
Space Complexity
The solution is completely iterative.
No recursion or extra data structures are used.
Space Complexity: O(1)
Why This Works
The BST property eliminates half of the remaining search space at every step.
Instead of exploring both subtrees like we would in a normal binary tree, we always know exactly which direction to move.
The moment the two nodes no longer lie on the same side—or when the current node matches one of them—we've reached the first node common to both paths.
That's exactly what the Lowest Common Ancestor is.
Interview Tips
This is the standard interview solution.
Interviewers are testing whether you recognize that this is a BST, not just a binary tree.
A common mistake is writing the generic Binary Tree LCA solution (O(n)), which recursively searches both subtrees. While that solution is correct, it ignores the BST property and misses the intended optimization.
Whenever you see Binary Search Tree, always ask yourself:
"Can I use the BST ordering to avoid searching the whole tree?"
In this problem, the answer is yes, leading to a simple iterative solution with O(h) time and O(1) space.