The Problem
Given a binary search tree (BST), find the lowest common ancestor (LCA) node of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes
p
andq
as the lowest node inT
that has bothp
andq
as descendants (where we allow a node to be a descendant of itself).”
Examples
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
Output: 6
Explanation: The LCA of nodes 2 and 8 is 6.
Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
Output: 2
Explanation: The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
Input: root = [2,1], p = 2, q = 1
Output: 2
Constraints
- The number of nodes in the tree is in the range [2, 10⁵].
- -10⁹ <= Node.val <= 10⁹
- All Node.val are unique.
- p != q
- p and q will exist in the BST.
Recursive Solution
func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? {
if root == nil || p == nil || q == nil {
return nil
}
if (max(p!.val, q!.val)) < root!.val {
return lowestCommonAncestor(root?.left, p, q)
} else if (min(p!.val, q!.val)) > root!.val {
return lowestCommonAncestor(root?.right, p, q)
} else {
return root
}
}
Explanation
If we slightly rephrase the definition of the problem: we need to find the split where both p
and q
nodes are in different subtrees.
To do that, we need to determine in which subtree we can find the p
or q
nodes.
For example, for nodes with p = 2, q = 8
, the LCA will be 6
.
Time/Space Complexity
- Time complexity: O(h)
- Space complexity: O(h)
Whereh
is the height of the tree.
Iterative Solution
func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? {
var curr = root
if p == nil {
return nil
}
if q == nil {
return nil
}
while curr != nil {
if p!.val < curr!.val && q!.val < curr!.val {
curr = curr?.left
} else if p!.val > curr!.val && q!.val > curr!.val {
curr = curr?.right
} else {
return curr
}
}
return root
}
Explanation
We can solve this problem using iteration. This solution is more memory-efficient because you don’t have recursive stack calls that take additional memory.
The algorithm looks like this:
- Compare
p
andq
values with thecurr
value.- If they are less than
curr
, move to theleft
subtree. - If they are greater than
curr
, move to theright
subtree. - If one is less and the other is greater (or either equals
curr
), we’ve found the LCA.
- If they are less than
Time/Space Complexity
- Time complexity: O(h) - where
h
is the height of the tree - Space complexity: O(1)