InterviewPrepKit

Home / Coding / Trees

Lowest Common Ancestor of a Binary Tree

medium Original ↗
Solving tips
  • No BST ordering here, so you must search: use a single post-order recursion that bubbles up found targets. O(n) time, O(h) space.
  • Define dfs to return p or q if the node is one of them, else the node itself if BOTH child calls return non-null, else whichever single child call is non-null (left or right).
  • The first node whose left and right calls both return non-null is the deepest common ancestor — post-order guarantees deepest-first.
  • Pitfall: don't forget the 'left or right' fallback (dropping it loses a found target), and compare by node identity (is), not by value; don't try to steer by value comparison (that's the BST variant).

Problem

Given the root of a binary tree (no ordering property this time) and two nodes p and q that both exist in the tree, return their lowest common ancestor: the deepest node whose subtree contains both. A node may be its own ancestor, so if q sits inside p’s subtree, the answer is p. All values are distinct.

Examples

  • Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 → Output: 3 5 and 1 are the root’s two children; only 3 contains both.
  • Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 → Output: 5 4 is a descendant of 5, so 5 is its own ancestor and the LCA.
  • Input: root = [1,2], p = 1, q = 2 → Output: 1 The root contains both nodes; nothing deeper does.

Constraints

  • 2 <= n <= 10^5 nodes; all values distinct; p != q, both guaranteed present.
  • No BST property — you cannot steer by comparing values.
  • Expected: a single O(n) traversal; nodes have no parent pointers.

Think about it first

Hint 1 If you knew, for each subtree, whether it contains `p` or `q`, how would you recognize the LCA node?
Hint 2 The LCA is the deepest node where the two targets appear in *different* places: one in the left subtree and one in the right — or the node itself is one target and its subtree holds the other.
Hint 3 Write a recursion that returns: `p` or `q` if the current node is one of them, else whichever child call returned non-null (or the node itself if *both* children returned non-null). That single postorder pass is the whole answer.
Your workspace Not runnable by design — this is your interview scratchpad. Saved on this device.