Skip to content

Lowest Common Ancestor of a Binary Search Tree

Given a binary search tree (BST) of unique values and two nodes p and q, return the lowest common ancestor (LCA) of the two nodes in the BST.

The lowest common ancestor between two nodes p and q is the lowest node in a tree T such that both p and q are descendants of node (where we allow a node to be a descendant of itself).

InputpqOutputExplanation
Tree: 6, 2→8, 0, 4→7, 9, 3, 52866 is the LCA of 2 and 8
Tree: 6, 2→8, 0, 4→7, 9, 3, 52422 is the LCA of 2 and 4 (one node is ancestor of the other)
Tree: 2, 1, 31322 is the LCA of 1 and 3
  • The number of nodes in the tree is in the range [2, 10^5].
  • -10^9 <= Node.val <= 10^9
  • All Node.val are unique.
  • p != q
  • Both p and q exist in the BST.
ApproachTimeSpaceKey IdeaBest When
RecursiveO(log n) avg, O(n) worstO(h)Use BST property to prune search spaceStandard — elegant, leverages BST structure
IterativeO(log n) avg, O(n) worstO(1)Same logic without recursion stackMemory-constrained, prefer iteration
  • Pick Recursive if you want clarity and simplicity (most interviewers prefer this).
  • Pick Iterative if you want to optimize space or demonstrate understanding of iteration.
Standard & Elegant
Recursive
O(log n) avg · O(h) space
Space Optimized
Iterative
O(log n) avg · O(1) space
★ Recommended

Leverage the BST property: compare current node value with both p and q. If both are smaller, recurse left. If both are larger, recurse right. Otherwise, the current node is the LCA.

The elegance comes from the fact that the BST structure guarantees a convergence point where the two nodes “split” — this point is the LCA.

⏱ Time O(log n) Binary search-like 💾 Space O(h) Recursion stack

Input: BST with root = 6, p = 2, q = 8

StepCurrent Nodep vs Nodeq vs NodeAction
162 < 68 > 6p and q on different sides → return 6

Result: LCA = 6 ✓

Input: BST with root = 6, p = 2, q = 4

StepCurrent Nodep vs Nodeq vs NodeAction
162 < 64 < 6Both in left subtree → recurse left
222 == 24 > 2p and q on different sides → return 2

Result: LCA = 2 ✓

Animated walkthrough

How recursive approach finds the LCA

Navigate down the tree using BST property. When p and q diverge (one left, one right), you've found the LCA.

Step 1 of 2 Target: 6
Waiting to begin...
Array state
Memory / lookup state

function lowestCommonAncestorRecursive(root, p, q):
if root.val > p.val and root.val > q.val:
// Both p and q are in left subtree
return lowestCommonAncestorRecursive(root.left, p, q)
elif root.val < p.val and root.val < q.val:
// Both p and q are in right subtree
return lowestCommonAncestorRecursive(root.right, p, q)
else:
// p and q are on different sides or one is root
return root
lowest_common_ancestor_bst_recursive.py
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def lowest_common_ancestor_recursive(root: Optional[TreeNode], p: TreeNode, q: TreeNode) -> TreeNode:
"""
Recursive approach to find LCA in a BST.
Exploit BST property: if both p and q are in left subtree, LCA is in left.
If both in right subtree, LCA is in right. Otherwise, current node is LCA.
Time: O(log n) average, O(n) worst case (skewed tree)
Space: O(h) - recursion stack, h = height
"""
if root.val > p.val and root.val > q.val:
# Both p and q are in left subtree
return lowest_common_ancestor_recursive(root.left, p, q)
elif root.val < p.val and root.val < q.val:
# Both p and q are in right subtree
return lowest_common_ancestor_recursive(root.right, p, q)
else:
# p and q are on different sides or one of them is root
return root
# Test cases
if __name__ == "__main__":
# Example 1: LCA of 2 and 8 in tree [6, 2, 8, 0, 4, 7, 9, null, null, 3, 5]
root = TreeNode(6)
root.left = TreeNode(2)
root.right = TreeNode(8)
root.left.left = TreeNode(0)
root.left.right = TreeNode(4)
root.left.right.left = TreeNode(3)
root.left.right.right = TreeNode(5)
root.right.left = TreeNode(7)
root.right.right = TreeNode(9)
p = root.left
q = root.left.right
result = lowest_common_ancestor_recursive(root, p, q)
print(result.val) # 2
# Example 2: LCA of 2 and 4
p = root.left
q = root.left.right
result = lowest_common_ancestor_recursive(root, p, q)
print(result.val) # 2
🎯 Interview Favourite

Same logic as the recursive approach, but implemented with a while loop instead of recursion. Navigate the tree by comparing node values with p and q, moving left or right until convergence.

This approach avoids the recursion stack entirely, useful when stack depth is a concern or when iterative solutions are preferred.

⏱ Time O(log n) Binary search-like 💾 Space O(1) No extra structure

Same as Approach 1, but using a while loop instead of recursion:

IterationCurrent Nodep vs Nodeq vs NodeAction
162 < 68 > 6p and q on different sides → return 6
function lowestCommonAncestorIterative(root, p, q):
current = root
while current is not null:
if current.val > p.val and current.val > q.val:
// Both in left subtree
current = current.left
elif current.val < p.val and current.val < q.val:
// Both in right subtree
current = current.right
else:
// Divergence point found
return current
return root
lowest_common_ancestor_bst_iterative.py
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def lowest_common_ancestor_iterative(root: Optional[TreeNode], p: TreeNode, q: TreeNode) -> TreeNode:
"""
Iterative approach to find LCA in a BST.
Same logic as recursive but using a while loop.
Leverage BST property to navigate toward convergence point.
Time: O(log n) average, O(n) worst case (skewed tree)
Space: O(1) - only using constant extra space
"""
current = root
while current:
if current.val > p.val and current.val > q.val:
# Both p and q are in left subtree
current = current.left
elif current.val < p.val and current.val < q.val:
# Both p and q are in right subtree
current = current.right
else:
# p and q are on different sides or one of them is current
return current
return root
# Test cases
if __name__ == "__main__":
# Example 1: LCA of 2 and 8 in tree [6, 2, 8, 0, 4, 7, 9, null, null, 3, 5]
root = TreeNode(6)
root.left = TreeNode(2)
root.right = TreeNode(8)
root.left.left = TreeNode(0)
root.left.right = TreeNode(4)
root.left.right.left = TreeNode(3)
root.left.right.right = TreeNode(5)
root.right.left = TreeNode(7)
root.right.right = TreeNode(9)
p = root.left
q = root.left.right
result = lowest_common_ancestor_iterative(root, p, q)
print(result.val) # 2
# Example 2: LCA of 2 and 4
p = root.left
q = root.left.right
result = lowest_common_ancestor_iterative(root, p, q)
print(result.val) # 2
✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
lowest_common_ancestor_of_a_binary_search_tree_space_optimized.py
def solution(): return 0