Divide and Conquer on Trees
What is this?
Lots of hard-looking tree questions melt away with one habit: solve the small pieces first, then combine. You visit the deepest nodes, get an answer for each little branch, and let those answers bubble back up to their parent β the way you'd add up the cost of every room to get the cost of a whole house. Each spot in the tree returns one number upward while quietly keeping score of the best answer seen so far.
π‘ Fun fact: This bottom-up combining is a baby version of dynamic programming β you compute each subproblem exactly once, so even a giant tree is solved in a single sweep.
π The 6 problems in this chapter are free. Sign in with Google or Microsoft to start solving.
Core idea: A huge family of tree problems is solved by one move: a post-order DFS where each call returns a single value to its parent, while updating a shared (global/nonlocal) answer that may combine both children. The return value is what a parent can extend; the answer is what bends at the current node. Spotting which information flows up (returned) versus down (passed as arguments) is the whole skill.
The pattern
The recurring tension: a parent can only continue one branch through a child, but the optimal answer often uses both branches meeting at a node. So you return one, but score with both.
The problems
- Diameter, Max Path Sum, Longest Univalue Path β the canonical trio: return an arm/height/gain upward, update the answer with
left + right. - Smallest Subtree with all the Deepest Nodes β return a richer tuple
(depth, covering-node); equal child depths mean this node is the answer. - LCA II β fuse an existence check into the search with a found-counter, trusting the result only if both targets were truly seen.
- Maximum Difference Between Node and Ancestor β the mirror image: information flows down (carry the path min/max as arguments).
Key takeaways
- Post-order DFS: return one thing, update another β the engine behind diameter, path sum, and more.
- Return one branch upward; the answer may bend using both branches at a node.
- Richer return types (tuples, counters) collapse multi-pass solutions into one O(n) pass.
- Direction matters: bottom-up returns info; top-down carries info down as arguments.
- Why interviewers love it: it tests whether you can design what each recursive call communicates.
Order: Diameter β Maximum Path Sum β Longest Univalue Path β LCA II β Smallest Subtree of Deepest Nodes β Max Difference NodeβAncestor.
Maximum Difference Between Node and Ancestor
Core idea: The biggest gap between any node and one of its ancestors only ever involves the smallest or the largest value seen on the path down to it β so carry the running
minandmaxdown the tree and you never have to compare any pair directly.
Problem, rephrased
Picture a company org chart drawn as a tree: the CEO is the root, and each manager sits above their reports. Every person has a number stamped on them β say, their desk number, or a salary band. We say person a is an ancestor of person b if a sits somewhere strictly above b on the same chain (a parent, grandparent, great-grandparent, β¦ all the way up to the root).
We want the single biggest disagreement along any chain: over all (ancestor, descendant) pairs (a, b), what is the maximum of |a.val - b.val|?
Formally: given the root of a binary tree, return the maximum value |a.val - b.val| such that a is an ancestor of b.
Here's a small tree to anchor the rest of the lesson:
| (ancestor, descendant) | values | abs difference |
|---|---|---|
| (8, 1) | 8 and 1 | 7 |
| (8, 14) | 8 and 14 | 6 |
| (8, 13) | 8 and 13 | 5 |
| (3, 1) | 3 and 1 | 2 |
| (10, 13) | 10 and 13 | 3 |
The biggest of all such differences here is 7 (the pair 8 and 1).
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson