Lowest Common Ancestor of a Binary Tree
Problem Statement
You’re a family tree historian finding the lowest common ancestor (LCA) of two nodes in a binary tree. Given the root and nodes p and q, return their LCA. This medium-level recursive quest is a lineage hunt—trace paths to unite the branches!
Example
Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
Tree:
3 / \ 5 1 / \ / \ 6 2 0 8 / \ 7 4
Output: 3 (LCA of 5 and 1)
Input: p = 5, q = 4
Output: 5 (5 is ancestor of 4)
Input: root = [1,2], p = 1, q = 2
Output: 1
Code
Java
Python
JavaScript
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;
return left != null ? left : right;
}
}
class Solution:
def lowestCommonAncestor(self, root, p, q):
if not root or root == p or root == q:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left and right:
return root
return left if left else right
function lowestCommonAncestor(root, p, q) {
if (!root || root === p || root === q) return root;
let left = lowestCommonAncestor(root.left, p, q);
let right = lowestCommonAncestor(root.right, p, q);
if (left && right) return root;
return left || right;
}
Explanation
- DFS Insight: LCA is where paths to p and q split—found when both subtrees return nodes.
- Flow: Recurse left and right; if both return non-null, root is LCA; else, propagate non-null result.
- Example Walkthrough: [3,5,1], p=5, q=1 → left=5, right=1, root=3 is LCA.
- Edge Case: p or q is root, or one is ancestor of the other—handled naturally.
- Alternative: Store paths to p and q, find last common node—more space, same result.
Note
Time complexity: O(n), Space complexity: O(h). A recursive reunion—elegant and ancestral!
