INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS
01
00/18
01 / COVER STEP 13 · BINARY TREES
INVARIANT · STEP 13 · DECK 2 OF 3
READ THE SHAPE

Deck 1 gave you the four traversals; this deck turns them into answers. Almost every problem here is one traversal that returns a value up the tree (a height, a diameter, a path sum), while a single global variable watches for the best. The rest are views (what the tree looks like from the top, side, or straightened into levels) and paths & ancestors (root-to-leaf sums, lowest common ancestor, nodes at distance K). Learn the two shapes, bottom-up postorder and level-batched BFS, and eighteen problems collapse into a handful of patterns.

18Problems
5Families
17Units
17Live walks
← → ↑ ↓  or  W A S D  navigate SPACE next   DOUBLE-CLICK to advance I index   G goto problem   P predict H hide solutions   T close video   F fullscreen
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
02 / START HERE READ THIS ONE FIRST

HOW THIS DECK WORKS

This is not a list of problems. It is 17 learning units, and every one runs the same four beats. Go in order and the problems stop feeling random.

ASSUMEDA queue for every level-based unit. Stacks & Queues is step 09 and not built yet, so the batching trick is derived here.

01 INTROWhat the concept is, and what to watch for
02 VIDEOThe lecture, full-width in theatre mode
03 DRILLS2–4 questions checking the lecture landed
04 PROBLEMSThe sheet problems that concept unlocks

Moving around

← ↑Back a slide — or A / W → ↓Forward — or D / S / Space 2×clickDouble-click the right side to advance, left to go back. A single click never moves the deck. IThe index: every problem, clickable, with your progress GJump straight to a problem by its number FFullscreen

While you study

HHide solutions — blurs code and steps so you try first PPredict mode: call the next step before the animation plays it TClose the video — Esc works too ☐ ★Mark solved, or star to revisit. Both are saved automatically.

18 PROBLEMS · EVERY ONE LINKS TO LEETCODE TO SOLVE

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
03 / INDEX PRESS I FROM ANYWHERE

INDEX — ALL 18 PROBLEMS

Click any problem to jump straight to it. Solved ones turn green. Press I from anywhere to come back here. The number is the sheet's row, not your position — the deck teaches in the order that builds, so you will meet them slightly out of numerical sequence.

DEPTH & BOTTOM-UP · 04
STRUCTURE · 03
VIEWS BY LEVEL · 05
PATHS · 04
ANCESTORS · 02
SOLVED HAS A LEETCODE LINK
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
04 / SIGNALS WHEN YOU SEE X, REACH FOR Y

WHICH PATTERN, AND WHY

Eighteen problems, a handful of shapes. The cards are the phrase that selects the pattern: “height/diameter” → bottom-up postorder, “by level” → batched BFS, “path sum” → carry-the-path, “distance K” → tree-as-graph.

“HEIGHT / DEPTH / DIAMETER / BALANCED / BEST PATH”

one postorder that RETURNS a value up the tree, a global tracks the best

BOTTOM-UP POSTORDER + GLOBALO(n)
“SAME / SYMMETRIC / MIRROR / INVERT”

recurse on two nodes in lockstep, comparing structure and values

PAIRED RECURSIONO(n)
“BY LEVEL” / “ZIG-ZAG” / “RIGHT VIEW” / “WIDTH”

BFS with size-batches; one batch is one level, read left→right or reversed

LEVEL-BATCHED BFSO(n)
“VERTICAL / TOP / BOTTOM VIEW”

BFS carrying a horizontal column index; bucket nodes by column

BFS + COLUMN INDEXO(n log n)
“ROOT-TO-LEAF” / “PATH SUM” / “PRINT PATHS”

carry the path (or running sum) down; test or record it at a leaf

DFS CARRYING THE PATHO(n) · O(n²) to print
“LCA” / “DISTANCE K” / “NEAREST”

LCA is one bottom-up pass; distance-K turns the tree into a graph + BFS

ANCESTOR / TREE-AS-GRAPHO(n)
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
05 / CONSTRAINTS BEFORE YOU WRITE A LINE

READ THE ANSWER OFF THE CONSTRAINTS

Every problem here is one O(n) traversal. The bottom-up family returns a value up the tree while a global watches; the level family is BFS batched by queue.size(). The number to fear is index overflow (width) and recursion depth.

n ≤
BUDGET
WHAT THAT BUYS YOU
n ≤ 10³
O(n²)
re-traverse per node (naive diameter/balanced), fine only for tiny trees
n ≤ 10⁵
O(n)
ONE traversal that returns a value while a global watches, the home row here
n ≤ 10⁶
O(n)
still one pass; watch recursion DEPTH (O(h)) and index OVERFLOW in width
width w
O(w) space
BFS holds a whole level, up to O(n) for the widest level of a full tree
print all paths
O(n·h)
collecting every root-to-leaf path costs the path length per leaf

TREE PROBLEM ⇒ ONE O(n) PASS · BOTTOM-UP POSTORDER OR LEVEL-BATCHED BFS

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
06 / ROADMAP WHAT YOU ARE ABOUT TO DO

THE WHOLE RUN, 17 UNITS

Seventeen units. The depth family (one postorder, one global) opens; then structure comparisons, the views (BFS by level and by column), paths (carry-it-down and prefix-sum), and ancestors (LCA and tree-as-graph). Four are concept units, top/bottom view, boundary, burn, taught but not on LeetCode.

UNIT 01

Maximum Depth

▶ 8:052 DRILLS1 PROBLEM
UNIT 02

Balanced Tree

▶ 12:302 DRILLS1 PROBLEM
UNIT 03

Diameter

▶ 13:472 DRILLS1 PROBLEM
UNIT 04

Maximum Path Sum

▶ 17:502 DRILLS1 PROBLEM
UNIT 05

Same Tree

▶ 4:182 DRILLS1 PROBLEM
UNIT 06

Symmetric & Invert

▶ 9:202 DRILLS2 PROBLEMS
UNIT 07

Zig-Zag Level Order

▶ 8:212 DRILLS1 PROBLEM
UNIT 08

Right View & Next Pointers

▶ 13:282 DRILLS2 PROBLEMS
UNIT 09

Top View

▶ 10:302 DRILLSNO SHEET ROW
UNIT 10

Bottom View

▶ 13:132 DRILLSNO SHEET ROW
UNIT 11

Vertical Order

▶ 18:532 DRILLS1 PROBLEM
UNIT 12

Boundary Traversal

▶ 9:472 DRILLSNO SHEET ROW
UNIT 13

Maximum Width

▶ 22:412 DRILLS1 PROBLEM
UNIT 14

Root-to-Leaf Paths

▶ 11:002 DRILLS4 PROBLEMS
UNIT 15

Lowest Common Ancestor

▶ 14:092 DRILLS1 PROBLEM
UNIT 16

Nodes at Distance K

▶ 17:422 DRILLS1 PROBLEM
UNIT 17

Burn the Tree

▶ 18:242 DRILLSNO SHEET ROW
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
07 / WARMUP TWO SHAPES CARRY THE DECK

BOTTOM-UP POSTORDER · LEVEL-BATCHED BFS

DRILL 01 · RECALL

For every node you need a fact that depends on its subtrees. How tall they are, say. In what order must you visit nodes so that fact is always ready when you need it?

Children first, then the node. If a node's answer is built out of its subtrees' answers, it simply cannot be computed until both subtrees have reported, so the visit order is forced, not chosen. That bottom-up order is postorder, and it is why the first four units of this deck are the same function wearing different hats: each node returns one value to its parent, and a running best is updated on the way up.

DRILL 02 · RECALL

You are running BFS with a queue, popping a node and pushing its children. At the instant just before you start on level k, what is sitting in the queue?

Exactly level k, and nothing else. Level k−1 has all been popped, and the only things pushed while popping it were its children, which are precisely level k. So the queue's size at that moment is the level's node count: snapshot it, pop that many, and you have isolated one level as a group. Reverse the group for zig-zag, take its last for right view, measure it for width. units 07, 08 and 13 are all that one observation.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
08 / INTRO UNIT 01 · Maximum Depth

UNIT 01 — Maximum Depth

The maximum depth (height) is the archetype of the whole bottom-up family. A node's height is 1 + the larger of its two children's heights, with an empty subtree contributing 0. That's a two-line postorder: ask each child for its height, combine, return. Every harder problem in this group, balanced, diameter, max path sum. Is this same recursion with an extra thing tracked on the side.

THE QUESTION THIS LECTURE ANSWERS

HOW TALL IS THE TREE, AND WHY IS IT A POSTORDER?

height = 1 + max(L,R)empty = 0postordervalue returns upO(n)
WHAT TO WATCH FOR
  • 01height(node) = 1 + max(height(left), height(right)); empty = 0
  • 02IT'S A POSTORDER. YOU NEED BOTH CHILDREN'S HEIGHTS BEFORE THE NODE'S
  • 03THE RETURN VALUE FLOWS UP THE TREE, ONE NUMBER PER NODE
  • 04THIS EXACT SHAPE POWERS BALANCED, DIAMETER AND MAX PATH SUM
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
09 / VIDEO UNIT 01 · Maximum Depth

L14. Maximum Depth in Binary Tree

STRIVER A2Z
Maximum Depth
RUNTIME 8:05
AFTER THIS → 2 DRILLS · PROBLEM #01
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
10 / DRILL UNIT 01 · Maximum Depth

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Why is computing a node's height a postorder (children-first) operation?

The parent's answer needs the children's answers. 1 + max(leftH, rightH) can't be evaluated until both recursive calls return, which is the definition of postorder. Every 'combine your children's results at the node' computation is a postorder, the shape you'll reuse for the next three problems.

DRILL 02 · TRACE

A root with a left child that is a single leaf, and a right child that has one child (a chain of 2). What's the max depth (number of nodes on the longest root-to-leaf path)?

3. Left path: root + leaf = 2 nodes. Right path: root + child + grandchild = 3 nodes. Depth is the max, so 3. (LeetCode counts nodes; some texts count edges, which would be 2. Always check which the problem wants.)

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
11 / MECHANISM UNIT 01 · POSTORDER · CODE MIRRORED

POSTORDER. BOTH SUBTREES FIRST, THEN THE NODE

Postorder is left → right → root: a node is recorded only once both its subtrees are complete, so the root is always last. Badge #7 here. Same walk again, with the record line moved after both calls. This children-before-parent order is what you need whenever a node's answer is built out of its children's answers: deleting a tree, heights, sizes, any bottom-up tree DP. Half of deck 2's problems are a postorder in disguise.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
12 / PROBLEM #01 · DEPTH · EASY

Maximum Depth of Binary Tree

EASY depth ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Maximum depth / height of the tree.” The base case of the whole bottom-up family.

INTUITION

A node's depth is 1 plus the deeper of its two children. Recurse; an empty subtree is 0.

STEPS
  1. maxDepth(node): if node is null, return 0
  2. left = maxDepth(node->left); right = maxDepth(node->right)
  3. return 1 + max(left, right)
↕ SCROLL
// Height = 1 + the taller subtree; empty = 0.
int maxDepth(TreeNode* root) {
    if (root == nullptr) return 0;
    return 1 + max(maxDepth(root->left), maxDepth(root->right));
}
TIMEO(n)each node visited once
SPACEO(h)recursion depth = height
TRAP

Off-by-one between nodes and edges. LeetCode counts nodes on the longest path (empty tree = 0, single node = 1). If a variant asks for height in edges, it's one less. Decide which the problem wants before you code the base case.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
13 / INTRO UNIT 02 · Balanced Tree

UNIT 02 — Balanced Tree

A tree is height-balanced if, at every node, its two subtrees' heights differ by at most 1. The naive check computes height at each node. O(n²). The trick: make the height helper do double duty. It returns the height as usual, but returns a sentinel −1 the moment it discovers any imbalance below, and every caller short-circuits on −1. One postorder, O(n).

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU CHECK BALANCE IN ONE PASS, NOT O(n²)?

|L − R| ≤ 1 everywhere−1 sentinelheight + check in oneshort-circuitO(n)
WHAT TO WATCH FOR
  • 01BALANCED = |leftHeight − rightHeight| ≤ 1 AT EVERY NODE
  • 02OVERLOAD THE HEIGHT HELPER: RETURN −1 TO MEAN 'UNBALANCED BELOW'
  • 03IF A CHILD RETURNS −1, PROPAGATE −1 IMMEDIATELY (SHORT-CIRCUIT)
  • 04OTHERWISE RETURN 1 + max(L,R) AS NORMAL
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
14 / VIDEO UNIT 02 · Balanced Tree

L15. Check for Balanced Binary Tree

STRIVER A2Z
Balanced Tree
RUNTIME 12:30
AFTER THIS → 2 DRILLS · PROBLEM #02
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
15 / DRILL UNIT 02 · Balanced Tree

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

What makes the O(n) balanced check faster than the naive one?

One combined pass instead of a height() call per node. Folding the balance test into the height recursion, and returning −1 to abort as soon as any subtree is unbalanced. Visits each node a single time. The −1 sentinel doubles as both 'unbalanced' and a value the parent can cheaply test.

DRILL 02 · RECALL

Why return −1 specifically as the 'unbalanced' signal, rather than a separate boolean?

−1 is impossible as a height, so it's a safe out-of-band signal. Real heights are non-negative, so −1 unambiguously means 'unbalanced somewhere below' and rides the existing integer return, no extra boolean, no global. Each caller checks for it first and short-circuits, giving the single-pass O(n).

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
16 / MECHANISM UNIT 02 · BALANCED · CODE MIRRORED

A NODE CANNOT ANSWER BEFORE ITS CHILDREN DO

This is the shape behind most of deck 2, and it is worth meeting once slowly. Asking “how tall is this subtree?” is a question a node cannot answer on the way down. It has to wait for both children first. That dependency is what forces postorder; it is not a stylistic choice. Watch the leaves get their h1 badges before any parent gets anything, and the root answer last because it had to. The balance test then rides along free: since every node already knows both child heights, checking |L − R| ≤ 1 costs nothing extra, which is how an O(n²) check-height-at-every-node solution collapses to O(n).

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
17 / PROBLEM #02 · DEPTH · MED

Balanced Binary Tree

MED depth ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Is the tree height-balanced?” (every node's subtrees differ in height by ≤ 1). A height recursion with an early-exit sentinel.

INTUITION

Compute height as usual, but return −1 the instant any subtree is unbalanced; propagate −1 up so the whole check is one O(n) pass.

STEPS
  1. height(node): if null, return 0
  2. l = height(left); if l == −1, return −1
  3. r = height(right); if r == −1, return −1
  4. if abs(l − r) > 1, return −1
  5. return 1 + max(l, r); answer = height(root) != −1
↕ SCROLL
// Height helper returns -1 as an 'unbalanced below' sentinel.
int height(TreeNode* node) {
    if (node == nullptr) return 0;
    int l = height(node->left);
    if (l == -1) return -1;
    int r = height(node->right);
    if (r == -1) return -1;
    if (abs(l - r) > 1) return -1;        // unbalanced here
    return 1 + max(l, r);
}
bool isBalanced(TreeNode* root) {
    return height(root) != -1;
}
TIMEO(n)one combined height+balance pass
SPACEO(h)recursion depth
TRAP

Calling a separate height() at every node. O(n²). The naive check recomputes heights repeatedly; fold the balance test into one height pass with the −1 sentinel for O(n). Also propagate −1 immediately, don't compute the right subtree if the left already failed.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
18 / INTRO UNIT 03 · Diameter

UNIT 03 — Diameter

The diameter is the longest path between any two nodes (measured in edges), and it need not pass through the root. The insight: the longest path that bends at a node is leftHeight + rightHeight. So run the height recursion, and at every node update a global maximum with leftH + rightH. Crucially, the node still returns its height (1 + max), not its diameter. That return/track split is the whole lesson.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU FIND THE LONGEST PATH WHEN IT NEED NOT TOUCH THE ROOT?

diameter = max(L+R)return height, track diameterglobal maxbends at a nodeO(n)
WHAT TO WATCH FOR
  • 01THE PATH BENDING AT A NODE = leftHeight + rightHeight (IN EDGES)
  • 02UPDATE A GLOBAL max WITH THAT AT EVERY NODE
  • 03BUT RETURN THE HEIGHT (1 + max(L,R)) TO THE PARENT, NOT THE DIAMETER
  • 04ONE POSTORDER, O(n), NOT height() PER NODE
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
19 / VIDEO UNIT 03 · Diameter

L16. Diameter of Binary Tree

STRIVER A2Z
Diameter
RUNTIME 13:47
AFTER THIS → 2 DRILLS · PROBLEM #03
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
20 / DRILL UNIT 03 · Diameter

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

At each node, what value do you RETURN to the parent, and what value do you use to UPDATE the answer?

Return height, update diameter. The parent needs this node's height; the longest path through this node is leftH + rightH. Confusing the two, returning the diameter. Breaks the parent's height math and is the single most common diameter bug.

DRILL 02 · TRACE

On the perfect 7-node tree (root 1; 2,3; 4,5,6,7), what is the diameter in edges?

4 edges. The deepest bending path runs from a bottom-level leaf up to the root and back down to another bottom leaf: e.g. 4–2–1–3–6, four edges. At the root, leftHeight + rightHeight = 2 + 2 = 4, which is where the global max lands.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
21 / MECHANISM UNIT 03 · DIAMETER · CODE MIRRORED

THE ANSWER AT A NODE IS NOT WHAT THE NODE RETURNS

Diameter is the first problem where those two numbers come apart, and mixing them up is the classic bug. The longest path through a node uses both sides, L + R, but the value handed to the parent can only use one, because a path cannot fork. So the node updates a running best with L + R, then returns 1 + max(L, R). Same walk as the height above, same badges; only the extra bookkeeping line differs. Return L + R by mistake and you get a number that is too big and not a path at all.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
22 / PROBLEM #03 · DEPTH · MED

Diameter of Binary Tree

MED depth ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Diameter, longest path between any two nodes.” The path need not pass the root, so track a global while returning heights.

INTUITION

Run the height recursion; at each node the longest bending path is leftH + rightH. Update a global max with it. Return the node's height (1 + max), not its diameter.

STEPS
  1. global best = 0
  2. height(node): if null, return 0
  3. l = height(left); r = height(right)
  4. best = max(best, l + r) // path bending here (edges)
  5. return 1 + max(l, r); answer = best
↕ SCROLL
// Return height; update the global diameter with leftH + rightH.
int best = 0;
int height(TreeNode* node) {
    if (node == nullptr) return 0;
    int l = height(node->left);
    int r = height(node->right);
    best = max(best, l + r);              // longest path bending at node (edges)
    return 1 + max(l, r);                 // RETURN height, not diameter
}
int diameterOfBinaryTree(TreeNode* root) {
    best = 0; height(root); return best;
}
TIMEO(n)one height pass, global updated per node
SPACEO(h)recursion depth
TRAP

Returning the diameter instead of the height. The parent needs this node's height to compute its own; the diameter (leftH + rightH) is a side-effect tracked globally. Return the wrong one and every ancestor's math breaks. LeetCode measures the diameter in edges, which is exactly leftH + rightH.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
23 / INTRO UNIT 04 · Maximum Path Sum

UNIT 04 — Maximum Path Sum

Maximum path sum is the diameter idea with values and one extra move. The best path bending at a node is node->val + max(0, gainLeft) + max(0, gainRight). You clamp negative gains to 0 because a negative-sum branch is better skipped. Track that in a global. What a node returns upward is node->val + max(0, max(gainLeft, gainRight)). A path can only continue up through one child.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU FIND THE BEST-SUM PATH, WITH NEGATIVES IN PLAY?

gain = val + max child (clamped)through = val + bothclamp to 0one child continuesglobal
WHAT TO WATCH FOR
  • 01BEST THROUGH A NODE = val + max(0,leftGain) + max(0,rightGain) → GLOBAL
  • 02CLAMP EACH CHILD'S GAIN TO ≥ 0. DROP NEGATIVE BRANCHES
  • 03RETURN val + max(0, max(leftGain, rightGain)), ONLY ONE CHILD CONTINUES UP
  • 04A PATH BENDS AT ITS HIGHEST NODE; ABOVE THAT IT'S A STRAIGHT LINE
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
24 / VIDEO UNIT 04 · Maximum Path Sum

L17. Maximum Path Sum in Binary Tree

STRIVER A2Z
Maximum Path Sum
RUNTIME 17:50
AFTER THIS → 2 DRILLS · PROBLEM #04
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
25 / DRILL UNIT 04 · Maximum Path Sum

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Why do you clamp each child's returned gain with max(0, gain)?

A negative branch is worse than no branch. If extending into a child would lower the sum, you take 0 instead, effectively not going that way. Without the clamp, a strongly negative subtree corrupts every ancestor's best-sum, and the solution fails on any tree with negative node values (which the problem explicitly allows).

DRILL 02 · RECALL

Why does the RETURNED value use max(leftGain, rightGain) while the GLOBAL update uses leftGain + rightGain?

Bend here (both children) vs continue upward (one child). The answer candidate at a node bends there and uses both branches: val + L + R. But what you hand your parent must be a path that can extend further up, and a valid path can't fork, so it takes only the better child: val + max(L, R). Same return/track split as diameter, now with values.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
26 / MECHANISM UNIT 04 · MAXPATH · CODE MIRRORED

A PATH MAY BEND, BUT ONLY ONCE, AND ONLY HERE

Max path sum is diameter with weights, and it adds one more idea: a branch that contributes a negative total is simply not taken, so each child's gain is clamped with max(0, …). As before, the answer that may be recorded at a node (val + L + R. The path turning here) is different from what the node returns (val + max(L, R), a path that must keep going up). Follow the badges: node 3 records 16 but only returns 10, and the winning path bends at the root for 18.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
27 / PROBLEM #04 · DEPTH · HARD

Binary Tree Maximum Path Sum

HARD depth ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Maximum path sum, path may start and end anywhere.” Diameter with values, negatives allowed. Clamp and track a global.

INTUITION

Each node's best downward gain is val + max(0, better child). The best path bending at the node is val + max(0,left) + max(0,right). Track that globally. Return the gain (one child only).

STEPS
  1. global best = −infinity
  2. gain(node): if null, return 0
  3. l = max(0, gain(left)); r = max(0, gain(right)) // clamp negatives
  4. best = max(best, node->val + l + r) // bend here
  5. return node->val + max(l, r); answer = best
↕ SCROLL
// Clamp child gains to 0; track val+L+R, return val+max(L,R).
int best = INT_MIN;
int gain(TreeNode* node) {
    if (node == nullptr) return 0;
    int l = max(0, gain(node->left));    // drop a negative branch
    int r = max(0, gain(node->right));
    best = max(best, node->val + l + r); // best path bending at this node
    return node->val + max(l, r);        // a path continues up via ONE child
}
int maxPathSum(TreeNode* root) {
    best = INT_MIN; gain(root); return best;
}
TIMEO(n)one postorder, global updated per node
SPACEO(h)recursion depth
TRAP

Not clamping negative gains, or initialising best to 0. A negative child should contribute 0 (drop it), not its negative value. And best must start at −∞, not 0. A tree of all-negative values has a negative answer (the least-negative single node), which a 0 floor would wrongly beat.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
28 / INTRO UNIT 05 · Same Tree

UNIT 05 — Same Tree

Two trees are the same if they have identical structure and values. Recurse on the two roots in lockstep: if both are null, they match; if exactly one is null, or their values differ, they don't; otherwise recurse on (p.left, q.left) and (p.right, q.right). This paired recursion is the template for symmetric and invert too.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU COMPARE TWO TREES NODE-BY-NODE?

paired recursionboth null = matchone null = mismatchcompare valslockstep
WHAT TO WATCH FOR
  • 01RECURSE ON TWO NODES TOGETHER, SAME POSITION IN EACH TREE
  • 02BOTH null → MATCH · EXACTLY ONE null → MISMATCH · DIFFERENT val → MISMATCH
  • 03ELSE RECURSE (p.left,q.left) AND (p.right,q.right)
  • 04THIS PAIRED RECURSION IS THE BASE FOR SYMMETRIC & INVERT
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
29 / VIDEO UNIT 05 · Same Tree

L18. Check if two trees are Identical

STRIVER A2Z
Same Tree
RUNTIME 4:18
AFTER THIS → 2 DRILLS · PROBLEM #05
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
30 / DRILL UNIT 05 · Same Tree

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

What are the three base/short-circuit cases when comparing two nodes p and q?

Both-null true, one-null false, value-mismatch false. These three guards handle every way two trees can align or diverge at a position; passing all three means the current nodes agree and you descend. Getting the null cases right (both vs exactly-one) is what makes it correct on differently-shaped trees.

DRILL 02 · RECALL

Same Tree, Symmetric and Invert are all variations of one idea. What is it?

Paired / mirrored recursion. Same tree walks the two trees in the same orientation; symmetric walks one tree against itself in mirror orientation (left vs right); invert physically swaps each node's children. Seeing them as one template with different child-pairings is the point of grouping them.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
31 / MECHANISM UNIT 05 · SAMETREE · CODE MIRRORED

TWO TREES, ONE WALK, AND STRUCTURE IS CHECKED FIRST

The general form of the pair walk that unit 06 uses mirrored. The drawing is p and the badge on each node is what q holds at the same position, so a disagreement is visible where it happens, and && means nothing below it is ever visited. The line that matters most is the first one: null against non-null is already a difference, before any value is compared.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
32 / PROBLEM #05 · COMPARE · EASY

Same Tree

EASY compare ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Are two trees identical?” Structure and values must match, a paired recursion.

INTUITION

Compare the two roots together: both null is a match; exactly one null or unequal values is a mismatch; otherwise recurse on the two left children and the two right children.

STEPS
  1. isSame(p, q): if both null, return true
  2. if exactly one is null, or p->val != q->val, return false
  3. return isSame(p->left, q->left) AND isSame(p->right, q->right)
↕ SCROLL
// Compare two trees in lockstep.
bool isSameTree(TreeNode* p, TreeNode* q) {
    if (!p && !q) return true;            // both empty -> match
    if (!p || !q || p->val != q->val) return false;
    return isSameTree(p->left, q->left)
        && isSameTree(p->right, q->right);
}
TIMEO(n)each pair of positions visited once
SPACEO(h)recursion depth
TRAP

Mishandling the null cases. 'Both null' is a match (you reached the end together); 'exactly one null' is a mismatch (shapes differ). Collapsing these, e.g. returning false whenever either is null. Breaks on trees that legitimately end at the same place.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
33 / INTRO UNIT 06 · Symmetric & Invert

UNIT 06 — Symmetric & Invert

A tree is symmetric if its left and right subtrees are mirror images. Compare them with a paired recursion, but mirrored: match left.left against right.right, and left.right against right.left. Invert is the active cousin: at every node, swap its two children and recurse, producing the mirror tree that symmetric merely checks for.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU CHECK MIRROR SYMMETRY, AND PRODUCE THE MIRROR?

mirror pairingL.left ↔ R.rightswap childreninvert = build mirrorsymmetric = test mirror
WHAT TO WATCH FOR
  • 01SYMMETRIC: COMPARE left.LEFT ↔ right.RIGHT AND left.RIGHT ↔ right.LEFT
  • 02THE CROSS-PAIRING IS THE WHOLE TRICK. SAME-SIDE WOULD CHECK 'SAME TREE'
  • 03INVERT: swap(node.left, node.right) THEN RECURSE INTO BOTH
  • 04INVERT PRODUCES THE MIRROR; SYMMETRIC TESTS FOR IT
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
34 / VIDEO UNIT 06 · Symmetric & Invert

L25. Check for Symmetrical Binary Trees

STRIVER A2Z
Symmetric & Invert
RUNTIME 9:20
AFTER THIS → 2 DRILLS · PROBLEM #06, #07
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
35 / DRILL UNIT 06 · Symmetric & Invert

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

In the symmetric check, which children do you compare across the two subtrees?

Cross-pair: outer with outer, inner with inner. A mirror reflects left↔right, so the left subtree's left edge corresponds to the right subtree's right edge. Comparing same-side children instead tests whether the two subtrees are identical (Same Tree), which is a different question and passes only coincidentally symmetric trees.

DRILL 02 · RECALL

Invert Binary Tree in one line of logic per node. What is it?

Swap children, recurse. swap(node->left, node->right) at every node flips the tree horizontally. It's the constructive version of the symmetric check: invert one half and it should equal the other. Famous for a reason. It's three lines and a favourite warm-up.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
36 / MECHANISM UNIT 06 · SYMMETRIC · CODE MIRRORED

SYMMETRY IS A QUESTION ABOUT A PAIR, NOT A NODE

Every recursion so far carried one pointer. Symmetry cannot: asking “is this node mirrored?” is meaningless on its own, so the recursion carries two and compares them. The pairing is the whole problem, a mirror matches outside with outside: (a.left, b.right) and (a.right, b.left). Pair left with left instead and the check silently becomes “are these two subtrees identical”, which is Same Tree, a different question that happens to return true on symmetric-looking inputs. Invert the tree and you get the third member of the family: same two-pointer walk, but swapping instead of comparing.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
37 / PROBLEM #06 · COMPARE · EASY

Symmetric Tree

EASY compare ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Is the tree a mirror of itself?” Compare the two halves with a MIRRORED paired recursion.

INTUITION

Symmetry means the left subtree mirrors the right. Compare left.left with right.right and left.right with right.left, the cross-pairing. Base cases as in same-tree.

STEPS
  1. isMirror(a, b): if both null, return true
  2. if exactly one null, or a->val != b->val, return false
  3. return isMirror(a->left, b->right) AND isMirror(a->right, b->left)
  4. answer = root == null OR isMirror(root->left, root->right)
↕ SCROLL
// Mirror check: cross-pair the children.
bool isMirror(TreeNode* a, TreeNode* b) {
    if (!a && !b) return true;
    if (!a || !b || a->val != b->val) return false;
    return isMirror(a->left, b->right)   // OUTER pair
        && isMirror(a->right, b->left);  // INNER pair
}
bool isSymmetric(TreeNode* root) {
    return !root || isMirror(root->left, root->right);
}
TIMEO(n)each mirrored pair visited once
SPACEO(h)recursion depth
TRAP

Comparing same-side children (left.left with right.left). That checks whether the two subtrees are identical, not mirror images. Symmetry reflects across the centre, so it must be left.left ↔ right.right and left.right ↔ right.left. Same-side pairing passes only trees that happen to be symmetric AND identical-sided.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
38 / PROBLEM #07 · COMPARE · EASY

Invert Binary Tree

EASY compare ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Invert / mirror the tree.” Swap every node's two children.

INTUITION

At each node swap its left and right pointers, then recurse into both (order doesn't matter). The result is the mirror image, the very tree Symmetric tests against.

STEPS
  1. invert(node): if null, return null
  2. swap(node->left, node->right)
  3. invert(node->left); invert(node->right)
  4. return node
↕ SCROLL
// Swap children at every node.
TreeNode* invertTree(TreeNode* root) {
    if (root == nullptr) return nullptr;
    swap(root->left, root->right);
    invertTree(root->left);
    invertTree(root->right);
    return root;
}
TIMEO(n)each node visited once
SPACEO(h)recursion depth
TRAP

Swapping AFTER recursing without care, or forgetting to return the root. Swap then recurse, or recurse then swap. Both work as long as you swap each node exactly once. Just return the (unchanged) root pointer; the tree is mutated in place. It's the constructive twin of the Symmetric check.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
39 / INTRO UNIT 07 · Zig-Zag Level Order

UNIT 07 — Zig-Zag Level Order

Zig-zag (spiral) traversal is a level-order walk where the direction alternates each level: left-to-right, then right-to-left, and so on. Run the standard size-batched BFS, but keep a leftToRight flag; for a right-to-left level, place values into the level list from the back (or just reverse the level before appending). Everything else is ordinary level order.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU READ THE TREE IN A BOUSTROPHEDON (ALTERNATING) ORDER?

level order + flagflip each levelreverse odd levelsqueue unchangedO(n)
WHAT TO WATCH FOR
  • 01STANDARD LEVEL-BATCHED BFS, PLUS A leftToRight FLAG THAT FLIPS EACH LEVEL
  • 02LEFT-TO-RIGHT LEVELS: APPEND NORMALLY · RIGHT-TO-LEFT: REVERSE (OR FILL FROM THE BACK)
  • 03THE QUEUE STILL ENQUEUES CHILDREN LEFT-THEN-RIGHT AS ALWAYS
  • 04ONLY THE OUTPUT ORDER PER LEVEL CHANGES, NOT THE TRAVERSAL
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
40 / VIDEO UNIT 07 · Zig-Zag Level Order

L19. Zig-Zag / Spiral Traversal

STRIVER A2Z
Zig-Zag Level Order
RUNTIME 8:21
AFTER THIS → 2 DRILLS · PROBLEM #08
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
41 / DRILL UNIT 07 · Zig-Zag Level Order

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

For zig-zag, does the way you push children onto the queue change between levels?

Push order stays left-then-right; only the output flips. The queue must keep producing correct level-by-level order, so children always go on left-then-right. The zig-zag is purely a presentation choice on each level's collected values, reverse alternate levels. Fiddling with push order corrupts the levels below.

DRILL 02 · TRACE

On the 7-node tree (root 1; 2,3; 4,5,6,7), what is the zig-zag order?

1 · 3,2 · 4,5,6,7. Level 0 has just the root (1). Level 1 is read right-to-left, so [3, 2] instead of [2, 3]. Level 2 flips back to left-to-right: [4, 5, 6, 7]. Concatenated: 1, 3, 2, 4, 5, 6, 7. The mechanism slide runs the plain level order; zig-zag just reverses every other captured level.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
42 / MECHANISM UNIT 07 · LEVELORDER · CODE MIRRORED

LEVEL ORDER, BFS, ONE LEVEL AT A TIME, WITH A QUEUE

Level order is breadth-first: top to bottom, left to right, using a queue instead of recursion. Pop the front, record it, push its children to the back. Because a queue is FIFO, everything on one level is processed before anything on the next. watch the queue hold exactly the current frontier and nothing else. Read the queue's size at the start of a round and you have one level isolated, which is what zig-zag, right-side view and almost every 'by level' problem in deck 2 are built on.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
43 / PROBLEM #08 · VIEWS · MED

Binary Tree Zigzag Level Order Traversal

MED views ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Zig-zag / spiral level order.” Level order with the direction flipped each level.

INTUITION

Standard size-batched BFS, plus a leftToRight flag. On a right-to-left level, place values from the back of the level list (or reverse it before appending). Children still enqueue left-first.

STEPS
  1. BFS with a queue; leftToRight = true
  2. each level: read size; make a list of that size
  3. pop size nodes; index = leftToRight ? i : size−1−i; place val at that index
  4. push children left-then-right as usual; flip leftToRight
  5. append the level list to the result
↕ SCROLL
// Level order; reverse the placement on alternate levels.
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
    vector<vector<int>> res;
    if (!root) return res;
    queue<TreeNode*> q; q.push(root);
    bool leftToRight = true;
    while (!q.empty()) {
        int n = q.size();
        vector<int> level(n);
        for (int i = 0; i < n; i++) {
            TreeNode* node = q.front(); q.pop();
            int idx = leftToRight ? i : n - 1 - i;   // place, don't reorder queue
            level[idx] = node->val;
            if (node->left)  q.push(node->left);
            if (node->right) q.push(node->right);
        }
        leftToRight = !leftToRight;
        res.push_back(level);
    }
    return res;
}
TIMEO(n)each node enqueued/dequeued once
SPACEO(w)queue holds one level
TRAP

Alternating the push order instead of the output order. The queue must keep producing correct levels, so always enqueue children left-then-right. Only flip how you record each level (reverse the collected values). Reversing the queue logic scrambles every level below.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
44 / INTRO UNIT 08 · Right View & Next Pointers

UNIT 08 — Right View & Next Pointers

The right side view is what you see standing to the right of the tree: the last node of each level. Size-batched BFS gives it directly, the final node popped in each level round is that level's rightmost. (A DFS that visits right before left and records the first node seen at each new depth works too.) Populating next-right pointers is the same 'per level' idea made into links: connect each node to its right neighbour on the same level.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU GET THE RIGHTMOST NODE PER LEVEL, AND LINK NEIGHBOURS?

last per levelright-first DFSnode.next = right neighbourO(1) for perfect treelevel-based
WHAT TO WATCH FOR
  • 01RIGHT VIEW = LAST NODE OF EACH LEVEL (BFS) OR FIRST-AT-EACH-DEPTH IN RIGHT-FIRST DFS
  • 02NEXT POINTERS: WITHIN A LEVEL, node.next = THE NODE POPPED AFTER IT
  • 03FOR A PERFECT TREE, next CAN BE SET IN O(1) SPACE USING ALREADY-SET next LINKS
  • 04BOTH ARE 'PROCESS ONE LEVEL AT A TIME'
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
45 / VIDEO UNIT 08 · Right View & Next Pointers

L24. Right/Left View of Binary Tree

STRIVER A2Z
Right View & Next Pointers
RUNTIME 13:28
AFTER THIS → 2 DRILLS · PROBLEM #09, #10
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
46 / DRILL UNIT 08 · Right View & Next Pointers

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Using BFS, how do you capture the right-side view?

The last-popped node of each level. Since BFS drains a level left-to-right, the final pop in that level's batch is its rightmost node, exactly what's visible from the right. (Recording the first per level gives the left view instead.) A right-first DFS recording the first node at each new depth is the tidy recursive alternative.

DRILL 02 · RECALL

Populating next-right pointers on a PERFECT binary tree can be done in O(1) extra space. What's the key relation?

Wire the next level using the current level's next chain. For a node, its left child's neighbour is its right child; its right child's neighbour is the left child of the node's own next (if any). Walking each level via the next pointers you already set lets you connect the level below with no queue. O(1) space. (The BFS solution is O(n) space but works on any tree.)

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
47 / MECHANISM UNIT 08 · RIGHTVIEW · CODE MIRRORED

KEY EACH NODE, THEN DECIDE WHO KEEPS THE KEY

Right view, top view, bottom view, vertical order and maximum width are the same level-order walk. Each node gets a key, and the only thing that changes between the five problems is which node keeps a key when several compete for it. Here the key is the level and the rule is last wins, so every node overwrites its level's entry and the survivor is the rightmost. Flip that one word to first wins and, with no other change, you would be looking at the left view.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
48 / PROBLEM #09 · VIEWS · MED

Binary Tree Right Side View

MED views ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Right side view, the rightmost node of each level.” Size-batched BFS, take the last.

INTUITION

BFS by level; the last node popped in each level is its rightmost. Record it. (Equivalently, a right-first DFS recording the first node seen at each new depth.)

STEPS
  1. BFS with a queue by level
  2. each level: read size; loop size pops, pushing children
  3. when i == size−1 (last pop of the level), append node->val to the result
  4. return the result (one value per level)
↕ SCROLL
// The last node popped in each BFS level is the rightmost.
vector<int> rightSideView(TreeNode* root) {
    vector<int> res;
    if (!root) return res;
    queue<TreeNode*> q; q.push(root);
    while (!q.empty()) {
        int n = q.size();
        for (int i = 0; i < n; i++) {
            TreeNode* node = q.front(); q.pop();
            if (i == n - 1) res.push_back(node->val);   // rightmost of level
            if (node->left)  q.push(node->left);
            if (node->right) q.push(node->right);
        }
    }
    return res;
}
TIMEO(n)each node visited once
SPACEO(w)queue holds one level
TRAP

Assuming the right view is just the right spine. If the right subtree is shorter, a node from the LEFT subtree can be the rightmost at a deep level, so you can't simply follow right pointers. Take the last node of each BFS level (or, in right-first DFS, the first node at each new depth).

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
49 / PROBLEM #10 · VIEWS · MED

Populating Next Right Pointers in Each Node

MED views ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Connect each node to its right neighbour on the same level.” A perfect tree admits an O(1)-space wiring.

INTUITION

For a perfect tree, use the current level's next links to wire the level below: a node's left.next = its right; its right.next = node.next ? node.next.left : null. Walk level by level via next pointers, no queue.

STEPS
  1. start at the root; leftmost = root
  2. while leftmost has a left child (not the last level):
  3. walk the current level via next: set node->left->next = node->right
  4. set node->right->next = node->next ? node->next->left : null
  5. advance leftmost = leftmost->left
↕ SCROLL
// Perfect tree: wire level L+1 using level L's next chain. O(1) space.
Node* connect(Node* root) {
    Node* leftmost = root;
    while (leftmost && leftmost->left) {
        Node* node = leftmost;
        while (node) {
            node->left->next = node->right;
            node->right->next = node->next ? node->next->left : nullptr;
            node = node->next;               // walk the current level
        }
        leftmost = leftmost->left;           // drop to the next level
    }
    return root;
}
TIMEO(n)each node connected once
SPACEO(1)no queue. Uses the next links being built
TRAP

Reaching for a queue (O(n) space) when O(1) is expected. The BFS solution is correct and works on any tree, but the interview point of LC 116 (perfect tree) is the constant-space wiring: connect the next level using the next pointers you already set on the current one. For a non-perfect tree (LC 117) the same idea needs a dummy head per level.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
50 / INTRO UNIT 09 · Top View

UNIT 09 — Top View

The top view is the set of nodes visible from directly above, the first node encountered at each horizontal column. Give the root column 0, a left child col − 1, a right child col + 1. Run a BFS (level order) carrying each node's column; the first time a column appears, that node is on the top view. BFS (not DFS) is essential so the topmost node wins ties. It's a concept unit, the pattern, not a LeetCode row.

THE QUESTION THIS LECTURE ANSWERS

WHAT DOES THE TREE LOOK LIKE FROM STRAIGHT ABOVE?

horizontal columncol ± 1first per columnBFS for tiessort by col
WHAT TO WATCH FOR
  • 01COLUMN INDEX: ROOT = 0, LEFT = col−1, RIGHT = col+1
  • 02BFS CARRYING (node, col); THE FIRST NODE SEEN PER COLUMN IS ON TOP
  • 03BFS, NOT DFS, SO THE HIGHER (EARLIER) NODE WINS EACH COLUMN
  • 04OUTPUT COLUMNS LEFT TO RIGHT (SORT BY col)
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
51 / VIDEO UNIT 09 · Top View

L22. Top View of Binary Tree

STRIVER A2Z
Top View
RUNTIME 10:30
AFTER THIS → 2 DRILLS · CONCEPT UNIT
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
52 / DRILL UNIT 09 · Top View

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Why must the top view use BFS rather than DFS?

BFS guarantees the topmost node arrives first at each column. Top view wants the highest node per column; BFS visits by increasing depth, so the first node it sees in a column is the shallowest. DFS could descend into a deep node in that column before a shallower sibling, recording the wrong one. (Bottom view flips this: keep the LAST node per column.)

DRILL 02 · RECALL

How is bottom view different from top view in the same framework?

Keep the last node per column, not the first. Top view records a column only if unseen (first wins); bottom view updates the column every time (last wins), so the deepest node in each column survives. Same BFS, same column indexing, one flips 'first' to 'last'.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
53 / MECHANISM UNIT 09 · TOPVIEW · CODE MIRRORED

FIRST AT THIS DISTANCE MEANS HIGHEST

Key each node by horizontal distance, root 0, left child −1, right child +1, and keep only the first node seen at each distance. The reason that works is worth pausing on. BFS visits shallower nodes before deeper ones, so first at this distance is automatically highest at this distance, which is the definition of the top view. Watch node 5 arrive at hd 0 and get turned away. The root already owns that column. Do this with a DFS instead and the guarantee evaporates.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
54 / INTRO UNIT 10 · Bottom View

UNIT 10 — Bottom View

The bottom view is the mirror of the top view: the last (lowest) node at each horizontal column, seen from below. Same column indexing (root 0, left −1, right +1) and the same BFS carrying the column, but instead of keeping the first node per column, you overwrite the column with every node, so the deepest one wins. Output the columns left to right. Also a concept unit.

THE QUESTION THIS LECTURE ANSWERS

WHAT DOES THE TREE LOOK LIKE FROM STRAIGHT BELOW?

last per columnoverwritesame as top, flippedBFS depth ordersort by col
WHAT TO WATCH FOR
  • 01SAME COLUMN INDEXING AND BFS AS TOP VIEW
  • 02OVERWRITE THE COLUMN ENTRY WITH EVERY NODE. LAST (LOWEST) WINS
  • 03BFS ENSURES 'LAST' IS BY INCREASING DEPTH, LEFT-TO-RIGHT ON TIES
  • 04OUTPUT SORTED BY COLUMN
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
55 / VIDEO UNIT 10 · Bottom View

L23. Bottom View of Binary Tree

STRIVER A2Z
Bottom View
RUNTIME 13:13
AFTER THIS → 2 DRILLS · CONCEPT UNIT
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
56 / DRILL UNIT 10 · Bottom View

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Top view keeps the first node per column; bottom view keeps the last. Why does BFS make 'last' mean the correct node for bottom view?

Later in BFS = deeper. Because BFS advances level by level, every subsequent node in a given column is at least as deep as the previous. Overwriting therefore leaves the deepest node, the one you'd see looking up at the tree. Same machinery as top view, 'first' swapped for 'last'.

DRILL 02 · RECALL

What decides the left-to-right ordering of the two views' output?

Order the output by column index. Each column contributes one node (first for top, last for bottom); presenting them left to right means iterating columns from the minimum to the maximum index. An ordered map keyed by column does this for free. Depth selects the node; column places it.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
57 / MECHANISM UNIT 10 · BOTTOMVIEW · CODE MIRRORED

THE SAME WALK, ONE WORD DIFFERENT

Bottom view is top view with the guard deleted. Same queue, same horizontal-distance key, but the entry is overwritten every time, so the last node to arrive at each distance is the one left standing, and the last to arrive is the deepest. The two problems are if (!seen.count(hd)) apart. Compare this run against the top view slide: identical badges, identical queue, and hd 0 resolves to 6 here where it resolved to 1 there.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
58 / INTRO UNIT 11 · Vertical Order

UNIT 11 — Vertical Order

Vertical order generalises the views: output every node, grouped by column, and within a column ordered by row (depth), breaking ties by value (LeetCode's rule). Run a BFS carrying (row, col); bucket nodes into a map keyed by column, and within each column sort by (row, value). Then read columns left to right. It's the full picture the top and bottom views each take one slice of.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU LIST EVERY NODE GROUPED BY VERTICAL COLUMN?

(row, col)bucket by columnsort by (row, value)ordered mapO(n log n)
WHAT TO WATCH FOR
  • 01CARRY (row, col): ROOT (0,0), LEFT (row+1, col−1), RIGHT (row+1, col+1)
  • 02BUCKET NODES BY COLUMN IN AN ORDERED MAP
  • 03WITHIN A COLUMN, SORT BY (row, value). THE LEETCODE TIE-BREAK
  • 04READ COLUMNS LEFT TO RIGHT
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
59 / VIDEO UNIT 11 · Vertical Order

L21. Vertical Order Traversal

STRIVER A2Z
Vertical Order
RUNTIME 18:53
AFTER THIS → 2 DRILLS · PROBLEM #11
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
60 / DRILL UNIT 11 · Vertical Order

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Two nodes land in the same column at the same row (depth). How does LeetCode's vertical order break the tie?

Same column, same row ⇒ smaller value first. The ordering key inside a column is (row, value): deeper rows come after shallower, and ties at the same row are resolved by ascending value. This exact tie-break is what distinguishes LeetCode's 'Vertical Order Traversal' from the simpler top/bottom views (and it's why a plain BFS insertion order isn't quite enough).

DRILL 02 · RECALL

How do you compute a node's column, and why does it place vertical lines correctly?

Left is −1, right is +1 from the parent's column. A vertical line through the tree is a constant horizontal offset from the root; each left step decreases it and each right step increases it. Nodes sharing a column value lie on the same vertical line. The definition of the traversal. Top/bottom view are just the first/last node of each such column.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
61 / MECHANISM UNIT 11 · VERTICALORDER · CODE MIRRORED

STOP CHOOSING. KEEP THE WHOLE COLUMN

Vertical order drops the competition entirely. Every node is kept, grouped by horizontal distance, so the answer is a list of columns rather than one node per key. Top and bottom view are then just this result with the first or last element of each column taken. The detail that bites in the real problem is tie-breaking: two nodes can share a column and a level, and LeetCode wants those ordered by value. BFS gives you the row order for free, but not that final tie-break.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
62 / PROBLEM #11 · VIEWS · MED

Binary Tree Vertical Order Traversal

MED views ▶ SOLVE ON LEETCODE PREMIUM
SIGNAL — WHAT GIVES IT AWAY

“Vertical order traversal.” Group nodes by column; within a column order by (row, value).

INTUITION

BFS carrying (row, col): root (0,0), left (row+1, col−1), right (row+1, col+1). Bucket into an ordered map keyed by column; within each column sort by (row, value). Read columns left to right.

STEPS
  1. map: column → list of (row, value)
  2. BFS from (root, 0, 0); for each node push (row, val) into map[col]
  3. children: (row+1, col−1) and (row+1, col+1)
  4. for each column in sorted order, sort its list by (row, value), take the values
  5. return the columns left to right
↕ SCROLL
// BFS carrying (row, col); bucket by column, sort by (row, val).
vector<vector<int>> verticalTraversal(TreeNode* root) {
    map<int, vector<pair<int,int>>> cols;        // col -> (row, val)
    queue<tuple<TreeNode*,int,int>> q;
    q.push({root, 0, 0});
    while (!q.empty()) {
        auto [node, row, col] = q.front(); q.pop();
        cols[col].push_back({row, node->val});
        if (node->left)  q.push({node->left,  row + 1, col - 1});
        if (node->right) q.push({node->right, row + 1, col + 1});
    }
    vector<vector<int>> res;
    for (auto& [col, vec] : cols) {
        sort(vec.begin(), vec.end());            // by row, then value
        vector<int> colVals;
        for (auto& [row, val] : vec) colVals.push_back(val);
        res.push_back(colVals);
    }
    return res;
}
TIMEO(n log n)sorting within columns
SPACEO(n)the map of all nodes
TRAP

Forgetting the (row, value) tie-break. LeetCode's vertical order is stricter than a plain top-down bucket: two nodes in the same column AND same row must be ordered by ascending value. Sort each column by (row, value), not just insertion order. The usual reason a 'works on simple trees' solution fails.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
63 / INTRO UNIT 12 · Boundary Traversal

UNIT 12 — Boundary Traversal

The boundary traversal prints the tree's outline anti-clockwise: the left boundary (top-down, excluding leaves), then all leaves left-to-right, then the right boundary (bottom-up, excluding leaves). Each part is a small dedicated walk, and the care is in not double-counting the corners (root, and leaves that are also on a boundary). A concept unit. The technique matters more than any single judge problem.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU PRINT THE OUTLINE OF THE TREE ANTI-CLOCKWISE?

left boundaryall leavesright boundary reversedno double-countanti-clockwise
WHAT TO WATCH FOR
  • 01THREE PARTS: LEFT BOUNDARY (TOP-DOWN) · LEAVES (L→R) · RIGHT BOUNDARY (BOTTOM-UP)
  • 02EXCLUDE LEAVES FROM THE LEFT AND RIGHT BOUNDARY WALKS (THEY'RE IN THE LEAVES PART)
  • 03ADD THE ROOT ONCE; HANDLE THE SINGLE-NODE AND MISSING-CHILD EDGE CASES
  • 04EACH PART IS A SEPARATE SIMPLE TRAVERSAL
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
64 / VIDEO UNIT 12 · Boundary Traversal

L20. Boundary Traversal in Binary Tree

STRIVER A2Z
Boundary Traversal
RUNTIME 9:47
AFTER THIS → 2 DRILLS · CONCEPT UNIT
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
65 / DRILL UNIT 12 · Boundary Traversal

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Why are leaves deliberately excluded from the left- and right-boundary walks?

To avoid double-counting corner leaves. The three passes overlap at the corners: a leaf can sit at the end of the left boundary and also in the leaves list. By having the boundary walks skip leaves and letting the middle pass own all leaves, every node is emitted once. Off-by-one at these corners is the whole difficulty of boundary traversal.

DRILL 02 · RECALL

Why is the right boundary collected bottom-up (or reversed) rather than top-down?

Anti-clockwise means the right side goes upward. After the leaves (bottom, left-to-right), the outline climbs the right edge back to the root, so the right boundary must be emitted bottom-up. Collect it top-down and reverse, or recurse to the bottom and add on the way back. The direction is what makes it a continuous outline.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
66 / MECHANISM UNIT 12 · BOUNDARY · CODE MIRRORED

THREE PASSES, AND THE JOINS ARE THE PROBLEM

The anti-clockwise boundary is not one traversal. It is three stitched together: the left edge top-down, then every leaf left to right, then the right edge bottom-up, so it is collected normally and then reversed. Each pass is easy. What makes this a hard problem is the joins: a leaf sitting on the left or right edge belongs to the leaf pass, so phases 1 and 3 must exclude leaves or that node is emitted twice. The leaf pass is also a full traversal of the tree, not a walk along the bottom. The leaves of the middle subtrees are on the boundary too.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
67 / INTRO UNIT 13 · Maximum Width

UNIT 13 — Maximum Width

Maximum width is the largest number of nodes between the leftmost and rightmost node of any level, counting the nulls in between. The trick is to index nodes as in a heap: root gets index i, its children 2i and 2i+1. A level's width is lastIndex − firstIndex + 1. Run a BFS carrying indices; per level, width is the last minus first index. Normalise each level's indices (subtract the first) so they don't overflow.

THE QUESTION THIS LECTURE ANSWERS

HOW WIDE IS THE TREE, COUNTING THE GAPS?

heap indexing 2i/2i+1width = last − first + 1counts null gapsnormalise per leveloverflow
WHAT TO WATCH FOR
  • 01INDEX NODES LIKE A HEAP: node i HAS CHILDREN 2i AND 2i+1
  • 02LEVEL WIDTH = lastIndex − firstIndex + 1 (INCLUDES NULL GAPS)
  • 03BFS CARRYING (node, index); TRACK THE MIN AND MAX INDEX PER LEVEL
  • 04NORMALISE INDICES EACH LEVEL (SUBTRACT THE FIRST) TO AVOID OVERFLOW
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
68 / VIDEO UNIT 13 · Maximum Width

L28. Maximum Width of Binary Tree

STRIVER A2Z
Maximum Width
RUNTIME 22:41
AFTER THIS → 2 DRILLS · PROBLEM #12
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
69 / DRILL UNIT 13 · Maximum Width

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Why index nodes as 2i and 2i+1 instead of just counting nodes per level?

Heap indices number the empty positions too. Width includes the gaps, so you need positional indices, not a node tally. Assigning 2i/2i+1 gives each slot the number it would have in a complete tree; the leftmost and rightmost present nodes then bracket the full span including any nulls between them.

DRILL 02 · RECALL

Why subtract the first index of each level from all indices on that level?

Re-basing prevents index overflow without changing the width. Since the width is last − first + 1, only the differences matter. Subtracting each level's first index resets it to 0 and keeps children small, avoiding the exponential blow-up (and negative wrap-around) that 2i+1 causes at depth ~30. A classic silent overflow bug.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
70 / MECHANISM UNIT 13 · MAXWIDTH · CODE MIRRORED

INDEX THE NODES AS IF THE TREE WERE AN ARRAY

Width has to count the missing nodes between two present ones, so counting what is in the queue is wrong. Give each node the index a heap would: children of i are 2i and 2i+1. A level's width is then last − first + 1, gaps included, with no null bookkeeping at all. The trap is that those indices double every level and overflow a 32-bit int on a deep skewed tree, so the code subtracts the level's first index as it goes, keeping the numbers small.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
71 / PROBLEM #12 · VIEWS · MED

Maximum Width of Binary Tree

MED views ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Maximum width, counting null gaps.” Heap-index the nodes; width = last − first + 1.

INTUITION

BFS carrying a heap index (children 2i, 2i+1). Per level, width is the last index minus the first plus 1. Normalise each level's indices by subtracting the first to avoid overflow.

STEPS
  1. BFS carrying (node, index); start (root, 0)
  2. each level: read size; first = index of the first node this level
  3. for each node: normIdx = index − first; children get 2*normIdx and 2*normIdx+1
  4. width = lastIndex − firstIndex + 1; track the max
  5. return the max width
↕ SCROLL
// Heap indices; normalise per level to avoid overflow.
int widthOfBinaryTree(TreeNode* root) {
    if (!root) return 0;
    int best = 0;
    queue<pair<TreeNode*, unsigned long long>> q;
    q.push({root, 0});
    while (!q.empty()) {
        int n = q.size();
        unsigned long long first = q.front().second, last = first;
        for (int i = 0; i < n; i++) {
            auto [node, idx] = q.front(); q.pop();
            idx -= first;                        // re-base to avoid overflow
            last = idx;
            if (node->left)  q.push({node->left,  2 * idx});
            if (node->right) q.push({node->right, 2 * idx + 1});
        }
        best = max(best, (int)(last + 1));
    }
    return best;
}
TIMEO(n)each node visited once
SPACEO(w)queue holds one level
TRAP

Index overflow. Raw 2i+1 indexing doubles each level and blows past a 32-bit int around depth 30, giving negative widths. Re-base every level by subtracting its first index (Python ints are unbounded, but C++/Java need the normalisation or an unsigned 64-bit type).

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
72 / INTRO UNIT 14 · Root-to-Leaf Paths

UNIT 14 — Root-to-Leaf Paths

The path family all carry the path (or a running sum) down as you recurse and test or record it, usually at a leaf. Binary Tree Paths collects every root-to-leaf path string. Path Sum asks if any root-to-leaf sum equals a target. Path Sum II collects all such paths (backtracking). Path Sum III is different: count paths between any ancestor and descendant summing to a target, solved with a prefix-sum hashmap, the same trick as subarray-sum-equals-K on a tree.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU TEST, PRINT, OR COUNT PATHS THROUGH THE TREE?

carry path downtest at leafbacktrack (push/pop)prefix-sum mapleaf = both children null
WHAT TO WATCH FOR
  • 01CARRY THE PATH / RUNNING SUM DOWN; AT A LEAF, TEST OR RECORD IT
  • 02PATH SUM: return target == leaf->val AT A LEAF; SUBTRACT val ON THE WAY DOWN
  • 03PATH SUM II: BACKTRACK. Push, recurse, POP THE NODE AFTER
  • 04PATH SUM III: PREFIX-SUM + HASHMAP OF prefix→count (ANY DOWNWARD PATH)
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
73 / VIDEO UNIT 14 · Root-to-Leaf Paths

L26. Print Root to Node Path

STRIVER A2Z
Root-to-Leaf Paths
RUNTIME 11:00
AFTER THIS → 2 DRILLS · PROBLEM #13, #14, #15, #16
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
74 / DRILL UNIT 14 · Root-to-Leaf Paths

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

In Path Sum (root-to-leaf equals target), what is the base case, and how do you avoid a subtle bug at a node with one child?

Test the sum only at a genuine leaf. A root-to-leaf path ends at a leaf, so you compare the remaining target to node->val when both children are null. Returning at null instead would let a node with one child falsely 'complete' a path through its missing side. Subtract as you go, check at leaves.

DRILL 02 · RECALL

Path Sum III counts paths that go downward between ANY two nodes. Why does a prefix-sum hashmap solve it in O(n)?

Prefix sums along the current root-to-node path. A downward path summing to target and ending at the current node corresponds to an earlier ancestor whose prefix sum is current − target. A hashmap of prefix→count (added on the way down, removed on the way back, backtracking the map) counts them in O(1) per node. It's the tree version of subarray-sum-equals-K.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
75 / MECHANISM UNIT 14 · PATHS · CODE MIRRORED

THE POP IS THE ONLY LINE THAT MATTERS

Everything before this asked a node for a number. This family needs the route, so the path is carried down as a shared buffer, appended on the way in and emitted whole at every leaf. Because that buffer is shared, entering a node and failing to remove it on the way out leaks it into the sibling branch: leaf 5 would report 1>2>4>5 instead of 1>2>5. That single pop_back() is backtracking, and it is the whole difference between this and a wrong answer. Watch the PATH panel shrink every time the walk leaves a node.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
76 / PROBLEM #13 · PATHS · EASY

Binary Tree Paths

EASY paths ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Print all root-to-leaf paths.” Carry the path down; record it at each leaf.

INTUITION

DFS carrying the path so far. At a leaf, record the completed path. Backtrack the path as you return so siblings start clean.

STEPS
  1. dfs(node, path): if null, return
  2. append node->val to path
  3. if node is a leaf (both children null): record the path string
  4. else dfs(left, path); dfs(right, path)
  5. pop node->val from path (backtrack)
↕ SCROLL
// Carry the path down; emit it at each leaf.
void dfs(TreeNode* node, string path, vector<string>& res) {
    if (!node) return;
    path += to_string(node->val);
    if (!node->left && !node->right) { res.push_back(path); return; }
    path += "->";
    dfs(node->left, path, res);
    dfs(node->right, path, res);
}
vector<string> binaryTreePaths(TreeNode* root) {
    vector<string> res; dfs(root, "", res); return res;
}
TIMEO(n·h)each node visited once; building each path costs O(h)
SPACEO(h)recursion + path
TRAP

Recording at null or at one-child nodes instead of leaves. A root-to-leaf path ends at a genuine leaf (both children null). Passing the path by value auto-backtracks in the snippet above; if you share a mutable path, you must pop after recursing or paths bleed into siblings.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
77 / PROBLEM #14 · PATHS · EASY

Path Sum

EASY paths ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Does a root-to-leaf path sum to the target?” Subtract on the way down; test at a leaf.

INTUITION

Recurse subtracting the node's value from the remaining target. At a leaf, success is remaining == node value. Return true if either subtree succeeds.

STEPS
  1. hasPath(node, target): if null, return false
  2. if leaf (both children null): return target == node->val
  3. return hasPath(left, target − node->val) OR hasPath(right, target − node->val)
↕ SCROLL
// Root-to-leaf sum == target: subtract down, check at leaves.
bool hasPathSum(TreeNode* node, int target) {
    if (!node) return false;
    if (!node->left && !node->right) return target == node->val;
    return hasPathSum(node->left,  target - node->val)
        || hasPathSum(node->right, target - node->val);
}
TIMEO(n)each node visited once
SPACEO(h)recursion depth
TRAP

Returning true when reaching null, or testing at non-leaves. An empty child isn't a completed path, only test at a real leaf. Reaching null should return false, or a node with a single child would falsely 'complete' a path through its missing side (e.g. target reached at a node that still has one child).

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
78 / PROBLEM #15 · PATHS · MED

Path Sum II

MED paths ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Collect all root-to-leaf paths summing to the target.” DFS with backtracking.

INTUITION

Carry the current path and remaining target. At a leaf that hits 0, record a copy of the path. Push before recursing and pop after. The backtracking that lets siblings reuse the path buffer.

STEPS
  1. dfs(node, target, path): if null, return
  2. push node->val to path; target −= node->val
  3. if leaf and target == 0: record a copy of path
  4. else dfs(left, target, path); dfs(right, target, path)
  5. pop from path (backtrack)
↕ SCROLL
// Backtracking: push, recurse, pop; record a copy at a matching leaf.
void dfs(TreeNode* node, int target, vector<int>& path,
         vector<vector<int>>& res) {
    if (!node) return;
    path.push_back(node->val);
    target -= node->val;
    if (!node->left && !node->right && target == 0)
        res.push_back(path);                 // a copy of the current path
    else {
        dfs(node->left,  target, path, res);
        dfs(node->right, target, path, res);
    }
    path.pop_back();                         // backtrack
}
vector<vector<int>> pathSum(TreeNode* root, int target) {
    vector<vector<int>> res; vector<int> path;
    dfs(root, target, path, res); return res;
}
TIMEO(n·h)each node once; copying a matching path costs O(h)
SPACEO(h)recursion + path
TRAP

Storing the path by reference, or forgetting to pop. Record a copy (path[:]). The shared buffer keeps mutating. And every push must be matched by a pop on the way out, or the path leaks into sibling branches. This is the canonical tree backtracking shape.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
79 / PROBLEM #16 · PATHS · MED

Path Sum III

MED paths ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Count paths (any node down to any descendant) summing to target.” Prefix-sum + hashmap.

INTUITION

Keep the running prefix sum from root to the current node and a map of prefix→count. Paths ending at the current node with sum = target correspond to an earlier prefix of (current − target). Add on the way down, remove on the way back.

STEPS
  1. map prefixCount = {0: 1}; running = 0, total = 0
  2. dfs(node): if null, return
  3. running += node->val; total += prefixCount[running − target]
  4. prefixCount[running]++; dfs(left); dfs(right)
  5. prefixCount[running]-- (backtrack the map); answer = total
↕ SCROLL
// Prefix-sum count: paths ending here with sum target.
int total = 0;
void dfs(TreeNode* node, long running, long target,
         unordered_map<long,int>& seen) {
    if (!node) return;
    running += node->val;
    total += seen.count(running - target) ? seen[running - target] : 0;
    seen[running]++;
    dfs(node->left, running, target, seen);
    dfs(node->right, running, target, seen);
    seen[running]--;                          // backtrack the map
}
int pathSum(TreeNode* root, int target) {
    total = 0; unordered_map<long,int> seen{{0,1}};
    dfs(root, 0, target, seen); return total;
}
TIMEO(n)each node visited once, O(1) map ops
SPACEO(n)the prefix map + recursion
TRAP

Not backtracking the prefix map, or seeding it wrong. After processing a node's subtrees you must decrement its prefix count, or sums from one branch pollute a sibling. Seed the map with {0: 1} so a path starting at the root counts. Use 64-bit sums. Values can be large and negative.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
80 / INTRO UNIT 15 · Lowest Common Ancestor

UNIT 15 — Lowest Common Ancestor

The lowest common ancestor of two nodes p and q in a general binary tree is found in one bottom-up pass. Base case: a null, or a node that is p or q, returns itself. Otherwise recurse into both children. If both return non-null, the two targets lie in different subtrees, so this node is the LCA; if only one side is non-null, propagate it up. No parent pointers, no second pass, O(n).

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU FIND THE SPLIT-POINT ANCESTOR OF TWO NODES IN ONE PASS?

node == p/q returns itselfboth sides non-null = LCApropagate one sideone passO(n)
WHAT TO WATCH FOR
  • 01BASE: null → null; node == p OR q → RETURN node ITSELF
  • 02RECURSE BOTH CHILDREN; COLLECT leftResult, rightResult
  • 03BOTH NON-NULL → THIS NODE IS THE LCA (TARGETS SPLIT HERE)
  • 04ONE NON-NULL → PROPAGATE IT UP (BOTH TARGETS ARE ON THAT SIDE)
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
81 / VIDEO UNIT 15 · Lowest Common Ancestor

L27. Lowest Common Ancestor

STRIVER A2Z
Lowest Common Ancestor
RUNTIME 14:09
AFTER THIS → 2 DRILLS · PROBLEM #17
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
82 / DRILL UNIT 15 · Lowest Common Ancestor

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

When does a node conclude that IT is the lowest common ancestor?

Both subtrees report a find ⇒ this is the split point. If p is somewhere on the left and q somewhere on the right (or vice versa), the current node is the deepest node that has both in its subtree. the LCA. If both were on one side, that side's recursion would return the answer and this node just forwards it. (The value-between-p-and-q rule is the BST version, a different problem.)

DRILL 02 · RECALL

Why does returning the node itself when node == p || node == q correctly handle the case where one target is an ancestor of the other?

Finding p first short-circuits correctly. When one target is above the other, the higher one (say p) is encountered first and returned; its subtree isn't explored further, but that's fine, p is an ancestor of q and thus their lowest common ancestor. The elegant part is that no special case is needed; the base case handles it.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
83 / MECHANISM UNIT 15 · LCA · CODE MIRRORED

WHERE TWO SEARCHES MEET IS THE ANSWER

The brute-force LCA finds both root-to-node paths and compares them. The elegant version never builds a path at all: search for either target, and let each call return what it found. A node that gets a hit back from its left side and its right side is, by definition, the deepest node containing both, so it returns itself. A node with only one hit just forwards it upward. The subtlety worth naming: this returns the first such node found on the way up, and going up means going from deepest to shallowest, which is exactly why it lands on the lowest common ancestor rather than the root.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
84 / PROBLEM #17 · ANCESTORS · MED

Lowest Common Ancestor of a Binary Tree

MED ancestors ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“Lowest common ancestor in a binary tree” (not a BST). One bottom-up pass.

INTUITION

Return the node if it's null or equals p or q. Recurse both sides; if both return non-null this node is the LCA, else propagate whichever side is non-null.

STEPS
  1. lca(node, p, q): if null or node == p or node == q, return node
  2. left = lca(node->left, p, q); right = lca(node->right, p, q)
  3. if both non-null, return node // targets split here
  4. return left ? left : right
↕ SCROLL
// Both subtrees report a target -> this node is the LCA.
TreeNode* lowestCommonAncestor(TreeNode* node, TreeNode* p, TreeNode* q) {
    if (!node || node == p || node == q) return node;
    TreeNode* left  = lowestCommonAncestor(node->left, p, q);
    TreeNode* right = lowestCommonAncestor(node->right, p, q);
    if (left && right) return node;          // p and q on different sides
    return left ? left : right;              // both on one side (or neither)
}
TIMEO(n)each node visited once
SPACEO(h)recursion depth
TRAP

Using the BST rule (compare values) on a general tree. A plain binary tree isn't ordered, so you can't navigate by value. You must search both subtrees. The 'both sides non-null ⇒ this is the LCA' logic also silently handles the case where one target is an ancestor of the other (it's found first and returned).

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
85 / INTRO UNIT 16 · Nodes at Distance K

UNIT 16 — Nodes at Distance K

All nodes at distance K from a target needs movement upward as well as down, but tree pointers only go down. So first turn the tree into a graph: one pass records each node's parent in a map. Now every node has three neighbours (left, right, parent), and the answer is a plain BFS from the target, stopping after K layers. The nodes on the K-th layer are exactly distance K away.

THE QUESTION THIS LECTURE ANSWERS

HOW DO YOU REACH NODES K STEPS AWAY, INCLUDING UPWARD?

parent maptree → graph3 neighboursBFS K layersvisited set
WHAT TO WATCH FOR
  • 01TREE POINTERS ONLY GO DOWN. YOU NEED TO GO UP TOO
  • 02FIRST PASS: BUILD A parent MAP (node → its parent)
  • 03NOW IT'S A GRAPH: EACH NODE'S NEIGHBOURS ARE left, right, parent
  • 04BFS FROM THE TARGET, K LAYERS DEEP; THE K-TH LAYER IS THE ANSWER (USE A visited SET)
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
86 / VIDEO UNIT 16 · Nodes at Distance K

L30. Nodes at a distance of K

STRIVER A2Z
Nodes at Distance K
RUNTIME 17:42
AFTER THIS → 2 DRILLS · PROBLEM #18
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
87 / DRILL UNIT 16 · Nodes at Distance K

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Why can't you solve 'all nodes at distance K' with a plain downward DFS from the target?

Distance-K nodes can lie above and across, not just below. From the target you must move to its parent (and then into the parent's other subtree) to reach some distance-K nodes. Tree links are one-directional (downward), so you first build a parent map, making every edge traversable both ways, then it's an ordinary unweighted-graph BFS.

DRILL 02 · RECALL

Once you have the parent map and BFS from the target, why is a visited set essential?

Undirected edges mean you can revisit. The visited set prevents it. With parent links added, moving target→parent→target is possible; without a visited set the BFS bounces between neighbours and mis-measures distances. Marking nodes visited as they're enqueued keeps the layer count equal to the true distance, so the K-th layer is exactly the answer.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
88 / MECHANISM UNIT 16 · DISTK · CODE MIRRORED

A TREE POINTS DOWN. GIVE IT EDGES THAT POINT UP

This is the moment binary trees stop being trees. “All nodes at distance K” needs to travel upward as well as downward, and a tree node has no pointer to its parent. So the first pass records one, and the tree becomes an undirected graph. After which the problem is nothing but a BFS from the target, layer by layer, stopping at layer K. Watch the spread reach node 2 from node 5: that step is impossible in any traversal in this deck, and it is the only new idea here. Distance-K and Burn the Tree are the same code with a different stopping condition.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
89 / PROBLEM #18 · ANCESTORS · MED

All Nodes Distance K in Binary Tree

MED ancestors ▶ SOLVE ON LEETCODE
SIGNAL — WHAT GIVES IT AWAY

“All nodes at distance K from a target.” Turn the tree into a graph, then BFS.

INTUITION

Child pointers only go down, but distance-K nodes can be above and across. Build a parent map, then BFS from the target over neighbours {left, right, parent}, K layers deep; the K-th layer is the answer.

STEPS
  1. pass 1: DFS/BFS to record parent[node] for every node
  2. BFS from target: queue = {target}, visited = {target}, dist = 0
  3. each layer: if dist == K, collect all queued node values and return
  4. else expand each node to left, right, parent (skip visited)
  5. dist++ per layer
↕ SCROLL
// Parent map turns the tree into a graph; BFS K layers from target.
vector<int> distanceK(TreeNode* root, TreeNode* target, int K) {
    unordered_map<TreeNode*, TreeNode*> parent;
    function<void(TreeNode*, TreeNode*)> mark = [&](TreeNode* n, TreeNode* p) {
        if (!n) return; parent[n] = p; mark(n->left, n); mark(n->right, n);
    };
    mark(root, nullptr);
    queue<TreeNode*> q; q.push(target);
    unordered_set<TreeNode*> seen{target};
    int dist = 0;
    while (!q.empty()) {
        if (dist == K) {
            vector<int> res;
            while (!q.empty()) { res.push_back(q.front()->val); q.pop(); }
            return res;
        }
        int n = q.size();
        for (int i = 0; i < n; i++) {
            TreeNode* node = q.front(); q.pop();
            for (TreeNode* nb : {node->left, node->right, parent[node]})
                if (nb && !seen.count(nb)) { seen.insert(nb); q.push(nb); }
        }
        dist++;
    }
    return {};
}
TIMEO(n)one pass to map parents, one BFS
SPACEO(n)parent map + visited set + queue
TRAP

Forgetting to go upward, or omitting the visited set. Distance-K nodes lie above and across, so you need the parent map, a downward-only DFS misses half of them. And once edges are bidirectional, BFS will bounce back the way it came unless a visited set blocks it, corrupting the distances.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
90 / INTRO UNIT 17 · Burn the Tree

UNIT 17 — Burn the Tree

Burn the tree (minimum time to burn everything, fire spreading to adjacent nodes each second, starting from a given node) is the distance-K idea taken to its limit: the answer is the maximum distance from the start node to any other node. Build the same parent map, then BFS outward from the start, counting the number of layers until the queue empties. That layer count is the burn time. A concept unit; the pattern is 'tree as graph + BFS'.

THE QUESTION THIS LECTURE ANSWERS

HOW LONG DOES FIRE TAKE TO CONSUME THE WHOLE TREE FROM A NODE?

fire = BFSparent mapmax distancelayer count = timetree as graph
WHAT TO WATCH FOR
  • 01FIRE SPREADS TO left, right AND parent EACH SECOND. AN UNDIRECTED GRAPH
  • 02BUILD THE parent MAP, THEN BFS OUTWARD FROM THE START NODE
  • 03COUNT THE NUMBER OF BFS LAYERS UNTIL EVERYTHING IS BURNT
  • 04ANSWER = THE MAX DISTANCE FROM START TO ANY NODE
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
91 / VIDEO UNIT 17 · Burn the Tree

L31. Minimum time to BURN the Tree

STRIVER A2Z
Burn the Tree
RUNTIME 18:24
AFTER THIS → 2 DRILLS · CONCEPT UNIT
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
92 / DRILL UNIT 17 · Burn the Tree

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Why is the minimum burn time equal to the maximum distance from the start node?

The last node to burn is the farthest one. Fire is a breadth-first wave: everything at distance d ignites at second d. The tree is fully consumed exactly when the most distant node ignites, so the answer is the maximum over all nodes of their distance from the start, computed by a BFS that counts layers. It's the same tree-as-graph machinery as distance-K.

DRILL 02 · RECALL

What is the shared engine behind 'nodes at distance K' and 'burn the tree'?

Parent map + BFS; one reads a layer, the other counts layers. Both problems need upward movement, so both build a parent map and BFS from a start node. Distance-K collects the nodes on the K-th layer; burn time is simply the index of the final layer. Recognising them as the same 'tree as graph' pattern is the payoff of grouping them.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
93 / MECHANISM UNIT 17 · BURN · CODE MIRRORED

THE SAME GRAPH, ASKED HOW LONG INSTEAD OF WHO

Burn the Tree is Distance-K with the question inverted. Fire spreads to a node's parent and both children each minute, the identical undirected-graph BFS, but instead of stopping at layer K and reporting who is there, you run until the queue empties and report how many layers it took. The answer is the eccentricity of the start node: the distance to the furthest node from it. Note the count starts at -1, because the layer containing the start node itself costs no time. An off-by-one that silently adds a minute if you miss it.

THE TREE
CALL STACK
RESULT · VISIT ORDER
CODE MIRROR
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
94 / RECALL RETRIEVAL, NOT RECOGNITION

NAME THE PATTERN FROM THE STATEMENT

DRILL 01 · TRANSFER

Diameter of a binary tree: why can't you just return the diameter recursively. Why does it need a global (or a returned pair)?

A node returns its height but records a diameter. Its parent needs the node's height to compute its own; but the longest path bending at this node is leftHeight + rightHeight. Those are different numbers, so you return one (height) and stash the other in a global max. This 'return X, track Y' split is the crux of the whole bottom-up family.

DRILL 02 · RECALL

Lowest Common Ancestor in a (non-BST) binary tree returns the node where the two targets split. What does the recursion return, and how does it detect the LCA?

Both sides non-null ⇒ this node is the split point. Base case: a null, or a node equal to p or q, returns itself. Each node collects its children's results, if the left subtree found one target and the right found the other, the current node is their lowest common ancestor; if only one side found anything, that result bubbles up. One O(n) pass, no parent pointers.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
95 / TRAPS PLAUSIBLE, WRONG, AND SILENT

SIX WAYS TO BE PLAUSIBLY WRONG

Tree bugs pass the sample and fail the judge: returning the diameter not the height, an unclamped negative gain, same-side symmetry, an overflowing width index, a level size read too late. Each returns a believable answer.

RETURNING THE DIAMETER INSTEAD OF THE HEIGHT

In the bottom-up family a node must return its height to its parent, while the answer (diameter, path sum) is tracked in a global. Return the answer by mistake and the parent's arithmetic is wrong, a classic and plausible bug that passes small symmetric trees.

NAIVE DIAMETER: O(n²)

Computing height separately at every node to get its diameter re-walks subtrees repeatedly, O(n²). Fold the diameter update INTO the single height recursion so each node is visited once.

MAX PATH SUM: NOT CLAMPING NEGATIVE GAINS TO 0

A child that contributes a negative sum should be dropped, not added. Take max(0, gain(child)). Forgetting the clamp makes a strongly negative subtree drag the answer down, and it fails on trees with negative values.

SYMMETRIC: COMPARING left-left INSTEAD OF left-right

Symmetry mirrors the two halves, so you compare the left subtree's LEFT with the right subtree's RIGHT, and left's right with right's left. Comparing same-side children checks 'same tree', not 'mirror', and passes only accidentally symmetric inputs.

MAX WIDTH: INTEGER OVERFLOW ON THE INDEX

Indexing nodes as 2i+1/2i+2 makes indices double each level and overflow for deep trees. Normalise each level by subtracting the first index (or use unsigned/long), or the width comes out negative.

READING queue.size() INSIDE THE LEVEL LOOP

The level count must be snapshotted before the inner loop; reading it live (as children are pushed) merges levels. This one silently corrupts zig-zag, right view, width, everything level-based.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
96 / CHEATSHEET REVISION SURFACE

ONE SCREEN, THE WHOLE DECK

Twelve patterns, one page. The right column is the phrase that should trigger each, the night-before surface for the property/view/path toolkit.

ALGORITHM
TIME
SPACE
REACH FOR IT WHEN
Max depth
O(n)
O(h)
1 + max(depth(left), depth(right))
Balanced
O(n)
O(h)
height helper returning −1 as an 'unbalanced' sentinel
Diameter
O(n)
O(h)
return height; global = max(global, leftH + rightH)
Max path sum
O(n)
O(h)
gain = val + max(0,L,R clamped); global = val + L + R
Same / Symmetric / Invert
O(n)
O(h)
paired recursion; mirror = left↔right children
Level order / zig-zag / right view
O(n)
O(w)
BFS, batch by queue.size(), reverse/last per level
Vertical / top / bottom view
O(n log n)
O(n)
BFS carrying a column index; bucket by column
Max width
O(n)
O(w)
index nodes 2i / 2i+1 per level; width = last − first + 1
Root-to-leaf paths / path sum
O(n)·O(n·h)
O(h)
carry path or running sum down; test at a leaf
Path sum III (any path)
O(n)
O(n)
prefix-sum count with a hashmap of prefix→count
LCA
O(n)
O(h)
both subtrees non-null ⇒ this node is the LCA
Nodes at distance K
O(n)
O(n)
parent map, then BFS K steps from the target
INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
97 / CLOSE STEP 13 · DECK 2 OF 3

READ THE SHAPE

Two shapes did most of the work: a bottom-up postorder that returns a value while a global watches (depth, diameter, path sum), and a level-batched BFS (views, width). Paths carry state down; LCA and distance-K reason about ancestors. Deck 3 finishes the topic, construction, serialization, Morris and tree DP.

00%
OF THIS DECK SOLVED
← ALL TOPICS← DECK 1 · TRAVERSALSSTEP 07 · RECURSION

Deck 2 of 3. Uses L14-L28, L30-L31. Top view, bottom view, boundary and burn tree are concept units (Striver lectures, no clean LC). Added at the user's request: Invert, Path Sum I/II/III, Populating Next Right. Children Sum Property (L29) dropped as niche. Deck 3 next.

INVARIANT · BINARY TREES · PROPERTIES, VIEWS & PATHS · DECK 2 OF 3
■ TOO SMALL TO READ
1280×720
INVARIANT · STEP 13 · DECK 2 OF 3

This one needs a laptop

Not a preference — an arithmetic one. Every slide is a fixed 1280 × 720 stage: a graph animating beside the code that drives it, with the problems laid out two columns wide. It scales as a single piece, so on a screen this size the body text comes out around 4px tall.

Shrinking it further would not help, and rebuilding it to reflow would mean losing the thing that makes it worth reading.

YOUR SCREEN0 × 0
NEEDED1060 × 610
WHAT IS WAITING ON THE LAPTOP
WATCH IT RUN, THEN RUN IT FROM MEMORY
Your progress is saved per device, so anything you tick on the laptop will be waiting there.