Lowest Common Ancestor of Binary Tree
Problem Statement
Given a binary tree and two nodes p and q, find their lowest common ancestor (LCA). The LCA is the lowest node in the tree that has both p and q as descendants (a node can be a descendant of itself).
Example:
3 / \ 5 1 / \ / \ 6 2 0 8 / \ 7 4 LCA(5,1) = 3 LCA(6,4) = 5
Approach 1: Recursive DFS
Explanation: Traverse tree recursively. If node is p or q, return it. Combine left and right results to find LCA.
Time Complexity: O(n)
Space Complexity: O(h) recursion stack
function LCA(root, p, q): if root == NULL or root == p or root == q: return root left = LCA(root.left, p, q) right = LCA(root.right, p, q) if left != NULL and right != NULL: return root return left if left != NULL else right
Approach 2: Parent Pointers + Ancestor Set
Explanation: Store parent of each node in a hash map. Trace ancestors of p, then first ancestor of q in the set is LCA.
Time Complexity: O(n)
Space Complexity: O(n)
parent = {root: NULL} stack = [root] while stack not empty: node = stack.pop() if node.left: parent[node.left] = node stack.push(node.left) if node.right: parent[node.right] = node stack.push(node.right) ancestors = set() while p != NULL: ancestors.add(p) p = parent[p] while q not in ancestors: q = parent[q] return q
Approach 3: Iterative DFS
Explanation: Use stack for DFS and store path to p and q. Compare paths to find last common node.
Time Complexity: O(n)
Space Complexity: O(n)
function findPath(root, target): stack = [(root,[root])] while stack: node, path = stack.pop() if node == target: return path if node.right: stack.push((node.right,path+[node.right])) if node.left: stack.push((node.left,path+[node.left])) pathP = findPath(root,p) pathQ = findPath(root,q) LCA = NULL for i in 0..min(len(pathP),len(pathQ))-1: if pathP[i] == pathQ[i]: LCA = pathP[i] else: break return LCA