Learning/Trees

Trees

15 questions, the largest section in the 150. Almost every one is the same recursion with a different combine step — so the work is learning to see which of four shapes a problem is.

The one skeleton

Java
ReturnType solve(TreeNode node) {
    if (node == null) return base;          // what an empty tree means
    ReturnType L = solve(node.left);
    ReturnType R = solve(node.right);
    return combine(node, L, R);
}

Every question here is a choice of base, combine, and ReturnType. Get comfortable stating the contract — "this call returns X for the subtree below it" — and then trusting it for the children.

The four shapes

1. Information flows UP. The parent combines what its children return. (Q1, Q2, Q3, Q4, Q5, Q6, Q12, Q14)

2. Information flows DOWN. A node needs context from its ancestors, passed as a parameter. (Q10, Q11, Q13)

3. Return one thing, record another. The answer at a node isn't extendable upward, so return what the parent can use and accumulate the answer separately. (Q3, Q14 — the two that feel hardest)

Return one thing, record another
Return one thing, record another

4. Breadth-first by level. Snapshot q.size() before enqueuing children. (Q8, Q9)

Snapshot the queue size before each level
Snapshot the queue size before each level

The three traversal orders

Where you touch the node is the only difference
Where you touch the node is the only difference

Only inorder has a special property: on a BST it emits values in sorted order. That single fact drives Q11 and Q12.

The BST property is worth using

A BST comparison at a node tells you which subtree a value is in, which turns searching into navigating:

ProblemWithout the BST propertyWith it
LCA (Q7)O(n) searchO(h) walk, O(1) space
Kth smallest (Q12)O(n log n) sortO(h + k), or O(h) with sizes
Validate (Q11)—inorder must be strictly increasing

And the validation trap: the property constrains a node by its whole ancestry, not its parent.

Every parent-child comparison passes, yet this is not a BST
Every parent-child comparison passes, yet this is not a BST

The traps

TrapSymptom
Comparing only parent and child (Q11)[5,4,6,null,null,3,7] wrongly accepted
int bounds in Validate BST (Q11)A lone Integer.MIN_VALUE node rejected
Checking balance only at the root (Q4)[1,2,2,3,3,null,null,4,4] wrongly accepted
Walking the right spine (Q9)Misses a rightmost node that sits in a left subtree
Strict > instead of >= (Q10)Ties undercounted
best = 0 instead of MIN_VALUE (Q14)All-negative tree returns 0
Forgetting int size = q.size() (Q8)All levels merge into one
Serializing without null markers (Q6, Q15)[1,2] and [1,null,2] become identical
Serializing without value delimiters (Q6)[12] wrongly reports containing [2]
Recursing right-before-left (Q13, Q15)Q13 throws; Q15 fails silently

Sentinels — and the discipline they need

Three questions overload a return value to carry two facts:

QuestionSentinelSafe because
Balanced (Q4)−1 means unbalancedHeights are never negative
Validate BST (Q11)Long.MIN/MAX boundsNode values are int, so they can't tie
Serialize (Q15)# means nullValues are integers, never #

In every case the sentinel works only because it lies outside the data's range. Check that explicitly — it's exactly where the trick silently breaks when reused.

Verification

Every Java snippet in this section was compiled and cross-checked against an independent implementation — 6,000+ randomized cases, including Q3 and Q4 against their own O(n²) brute force, Q7 against the general LCA algorithm, Q12 against the sorted inorder for every k, Q14 against an all-pairs path-sum brute force, and Q15 round-tripped in both formats.

Six deliberately-broken variants confirm the traps are real rather than theoretical: