INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS
01
00/12
01 / COVER STEP 16 · DYNAMIC PROGRAMMING
INVARIANT · STEP 16 · DECK 1 OF 4
WRITE THE RECURRENCE

Dynamic programming is recursion that stopped recomputing. Write the brute-force recursion first, express the problem in terms of an index, do every possible thing at that index, then take the max, min or sum the question asks for. Once that runs, three mechanical steps turn it into the answer an interviewer wants: memoize it, tabulate it, then throw the table away. Thirteen lectures, and the same four steps every single time.

12Problems
3Families
13Units
7Live benches
← → ↑ ↓  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 · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
02 / START HERE READ THIS ONE FIRST

HOW THIS DECK WORKS

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

ASSUMEDStriver's recursion playlist, lectures 6 and 7, pick / not-pick and counting ways at the base case. DP 1 names them as the prerequisite in its opening minutes and every unit here leans on them.

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.

12 PROBLEMS · 11 LINK TO A JUDGE · THE REST ARE CONCEPTS THE DRILLS COVER

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
03 / SIGNALS WHEN YOU SEE X, REACH FOR Y

READ THE STATEMENT, NAME THE RECURRENCE

Almost nobody fails a DP problem because they cannot fill a table. They fail because they cannot tell, from the statement, what the state should be. These six phrasings cover every problem in this deck, and the right-hand column is what each one permits you to write.

“COUNT THE NUMBER OF WAYS”

every route has to be counted, so you try them all and ADD. That is a sum recurrence

COUNT DP · base case returns 1O(n) or O(n·m)
“MINIMUM / MAXIMUM COST”, “CHEAPEST PATH”

try every option at this index and keep the best, a min or max recurrence

OPTIMISATION DP · out-of-range returns ±∞O(n) or O(n·m)
“NO TWO ADJACENT”

the only thing forbidden is the index you just came from, and the state already knows it

PICK / NOT-PICK · still one indexO(n)
“CANNOT REPEAT YESTERDAY’S”

what is forbidden is one of k named choices, so the state has to carry WHICH, false friend of the card on its left

PICK / NOT-PICK · one extra dimensionO(n·k)
A GRID, MOVING ONLY RIGHT AND DOWN

each cell is reachable from exactly two others, so the table has the grid's own shape

DP ON GRIDS · dp[i][j] from up and leftO(n·m)
“START ANYWHERE” / “END ANYWHERE”

no fixed origin means you loop the driver over every legal start and take the best

VARIABLE ENDPOINTS · answer is over a whole rowO(n·m)
TWO THINGS MOVING AT ONCE

solving them separately double-counts anything shared, so move them together

MULTI-AGENT DP · one index per moverO(n·m²)
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
04 / CONSTRAINTS BEFORE YOU WRITE A LINE

READ THE ANSWER OFF THE CONSTRAINTS

Read the target complexity off the bounds before designing the state. A DP's cost is (number of states) × (work per state), so the constraint is telling you how many indices you are allowed. Type a bound and the row it lands in rings gold.

n ≤
BUDGET
WHAT THAT BUYS YOU
n ≤ 20
O(2ⁿ)
plain recursion still fits. This is the only band where NOT memoizing is survivable
n ≤ 10³
O(n²)
2D DP: a table of n² states, each filled in O(1). Grids, LCS, MCM live here
n ≤ 10⁵
O(n)
1D DP: one state per index, one pass. Climbing stairs, house robber, LIS with binary search
n·m ≤ 10⁶
O(n·m)
a grid you can afford to fill completely, the home row for every problem in this deck
n ≤ 10⁶
O(1) space
the recurrence reads only the last row or two, so keep those and drop the table

n ≤ 20 is the one band where plain recursion survives, and it is also the signal for bitmask DP, which this sheet does not cover in any of the four decks.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
05 / WARMUP BEFORE ANY OF IT · 1 OF 2

WHAT MAKES A RECURSION WORTH A TABLE

DRILL 01 · RECALL

You write a recursion, it is correct, and it times out. Before reaching for a dp array, what has to be true of the problem?

Overlapping subproblems. Memoization only pays when the same call happens again. The mechanism is nothing more. A recursion whose branches never revisit a state (merge sort, say) gets nothing from a table however slow it is. The other half of the requirement, optimal substructure, is what lets you build the answer from subanswers at all.

DRILL 02 · RECALL

A DP over an array of size n with n ≤ 10⁵. Your table is dp[i][j] over all pairs. What has gone wrong?

Read the bound before designing the state. n ≤ 10⁵ buys about O(n log n); an n² table is 10¹⁰ cells and will not fit in memory, let alone time. The constraint is telling you the state has ONE index. Doing this arithmetic first is the habit. The next slide is a ladder for it.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
06 / WARMUP BEFORE ANY OF IT · 2 OF 2

WHAT MAKES A RECURSION WORTH A TABLE

DRILL 01 · BUG

Memoized recursion. It compiles and returns a number. One line makes the table useless, which?

int f(int i, vector<int>& dp){
    if(i <= 1) return i;
    if(dp[i] != -1) return dp[i];
    int r = f(i-1,dp) + f(i-2,dp);
    return r;
}

It reads the table and never writes it. Line 3 checks the cache and line 5 returns without filling it, so every lookup misses and the runtime stays exponential, while the code LOOKS memoized. Nothing crashes, nothing returns a wrong answer; it is simply as slow as the version you were replacing. Write it as return dp[i] = r; and the store cannot be forgotten.

DRILL 02 · RECALL

Tabulation is usually preferred over memoization in an interview even when both are O(n). Why?

The stack. Both use an O(n) table; memoization ALSO uses O(n) stack frames, and at n = 10⁶ that is where it dies. Tabulation is a loop, so the stack term disappears entirely, and only once the table is a loop can you notice it reads two cells and throw the table away too.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
07 / ROADMAP WHAT YOU ARE ABOUT TO DO

THE WHOLE RUN, 13 UNITS

Thirteen lectures, 6h 43m. The first six build the method on a single line of cells; the last seven put a second index on it and then a third. Unit 10 has no sheet row. It is the lecture where counting turns into optimising, and skipping it would leave the three units after it resting on an argument nobody made.

UNIT 01

THE METHOD

▶ 33:514 DRILLS1 PROBLEM
UNIT 02

1D RECURRENCE

▶ 13:173 DRILLS1 PROBLEM
UNIT 03

COST ON THE JUMP

▶ 38:503 DRILLS1 PROBLEM
UNIT 04

K TRANSITIONS

▶ 17:352 DRILLS1 PROBLEM
UNIT 05

PICK / NOT-PICK

▶ 32:233 DRILLS1 PROBLEM
UNIT 06

CIRCULAR ARRAYS

▶ 9:503 DRILLS1 PROBLEM
UNIT 07

THE 2D TURN

▶ 52:183 DRILLS1 PROBLEM
UNIT 08

DP ON GRIDS

▶ 48:293 DRILLS1 PROBLEM
UNIT 09

OBSTACLES

▶ 12:593 DRILLS1 PROBLEM
BEYOND THE SHEETUNIT 10

COUNT TO OPTIMISE

▶ 23:473 DRILLSNO SHEET ROW
UNIT 11

FIXED START, FREE END

▶ 34:393 DRILLS1 PROBLEM
UNIT 12

FREE START, FREE END

▶ 42:383 DRILLS1 PROBLEM
UNIT 13

3D DP

▶ 43:234 DRILLS1 PROBLEM
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
08 / INDEX PRESS I FROM ANYWHERE

INDEX — ALL 12 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.

Introduction to DP · 01
1D DP · 05
2D/3D DP and DP on Grids · 06
SOLVED HAS A JUDGE LINK CONCEPT — DRILLS ONLY
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
09 / INTRO UNIT 01 · THE METHOD

UNIT 01 — THE METHOD

Memoization, tabulation and space optimisation are three forms of one recurrence

THE QUESTION THIS LECTURE ANSWERS

WHY DOES A CORRECT RECURSION TAKE FOREVER, AND WHAT EXACTLY FIXES IT?

memoization = top-downtabulation = bottom-upoverlapping subproblemsoptimal substructure
WHAT TO WATCH FOR
  • 01THE PHRASE OVERLAPPING SUBPROBLEMS. IT IS THE ONLY CONDITION THAT MATTERS
  • 02MEMOIZED SPACE IS TWO COSTS: THE TABLE AND THE STACK. HE NAMES BOTH
  • 03THE ARRAY IS SIZED n+1, AND HE STOPS TO SAY WHY
  • 04THE LAST STEP KEEPS TWO VARIABLES, WATCH WHICH TWO
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
10 / VIDEO UNIT 01 · THE METHOD

DP 1 · Introduction to Dynamic Programming

STRIVER A2Z
Fibonacci four ways · overlapping subproblems · the complexity each step buys
RUNTIME 33:51
AFTER THIS → 4 DRILLS · PROBLEM #01
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
11 / DRILL UNIT 01 · THE METHOD · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The lecture names the exact condition that makes a problem worth memoizing. What is it called?

When f(2) is computed under f(4) and again under f(3), it is the SAME subproblem. 'the second Fibonacci number is going to be the same at any instance in the entire program'. That repetition is what memoization removes. Optimal substructure is real and also required, but it is not the word the lecture uses here.

DRILL 02 · RECALL

Memoized Fibonacci is O(n) time. What is its SPACE, as the lecture breaks it down?

Two separate costs, and the lecture insists on naming both: the dp array is O(n) AND the recursion stack is O(n). This matters because it is exactly the stack term that tabulation deletes, which is the whole reason the next step exists.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
12 / DRILL UNIT 01 · THE METHOD · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · BUG

This is the memoized Fibonacci from the lecture. One line will crash or silently return garbage. Which one?

int f(int n, vector<int>& dp){
    if(n <= 1) return n;
    if(dp[n] != -1) return dp[n];
    return dp[n] = f(n-1,dp) + f(n-2,dp);
}

int fib(int n){
    vector<int> dp(n, -1);
    return f(n, dp);
}

vector<int> dp(n, -1) holds indices 0..n-1, but f(n) writes dp[n]. The lecture is explicit that the array is declared with size n+1 precisely because the subproblems run 0 through n inclusive. Off by one, and it is the single most common way this code dies.

DRILL 02 · TRANSFER

After tabulation, the lecture space-optimises to two variables. What makes that legal for Fibonacci but NOT for every tabulated DP?

prev/prev2 works because dp[i] depends on dp[i-1] and dp[i-2] and nothing older. The moment a recurrence reaches further back (or reaches an arbitrary index, as Frog Jump with K does) the whole row has to stay alive. Space optimisation is a property of the RECURRENCE, not a step you always get to take.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
13 / MECHANISM UNIT 01 · LADDER · CODE MIRRORED

ONE RECURRENCE, FOUR FORMS

The same f(n) = f(n-1) + f(n-2), four times. Watch the call tree for fib(5) shrink as each step is applied, and watch what each step actually buys: memoization deletes the repeated calls, tabulation deletes the stack, and space optimisation deletes the table. Nothing about the recurrence changes.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
14 / CONCEPT #01 · INTRO · EASY

Introduction to DP

EASY intro CONCEPT · NO LEETCODE · DRILLS COVER IT
SIGNAL — WHAT GIVES IT AWAY

There is no statement to read. This row is the METHOD. Every later problem is these four steps applied to a recurrence you have just written.

INTUITION

A recursion that revisits the same subproblem is doing the same work twice. Store each answer the first time (memoization) and the tree collapses to a spine. Rewrite that as a bottom-up loop (tabulation) and the recursion stack goes too. Notice the loop only reads the last cell or two, keep those in variables, and the table goes as well.

STEPS
  1. Write the brute-force recursion. Do not optimise it yet. It defines the state.
  2. Add a dp array sized by the STATE, filled with a sentinel like −1.
  3. On entry, return dp[state] if it is set. On exit, WRITE it: return dp[state] = …
  4. Rewrite bottom-up: the base cases become initial values, the recursion a loop.
  5. Check how far back the loop reads. Reaches two cells? Keep two variables.
BRUTEO(2ⁿ)
OPTIMALO(n)
↕ SCROLL
// 1 - plain recursion: O(2^n)
int f(int n) { return n <= 1 ? n : f(n-1) + f(n-2); }

// 2 - memoization: O(n) time, O(n) table + O(n) stack
int f(int n, vector<int>& dp) {
    if (n <= 1) return n;
    if (dp[n] != -1) return dp[n];
    return dp[n] = f(n-1, dp) + f(n-2, dp);   // WRITE, not just return
}

// 3 - tabulation: O(n) time, O(n) table, no stack
vector<int> dp(n+1);                          // n+1, not n
dp[0] = 0; dp[1] = 1;
for (int i = 2; i <= n; i++) dp[i] = dp[i-1] + dp[i-2];

// 4 - space optimised: O(n) time, O(1) space
int p2 = 0, p1 = 1;
for (int i = 2; i <= n; i++) { int c = p1 + p2; p2 = p1; p1 = c; }
TIMEO(n)one pass over the states
SPACEO(1)after space optimisation, O(n) before it
TRAP

Reading the table and forgetting to write it. if(dp[i]!=-1) return dp[i]; followed by return f(i-1)+f(i-2); compiles, returns the right answer, and is still exponential. Write return dp[i] = … and it cannot happen.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
15 / INTRO UNIT 02 · 1D RECURRENCE

UNIT 02 — 1D RECURRENCE

Writing a 1D recurrence from the way a problem branches

THE QUESTION THIS LECTURE ANSWERS

HOW MANY DISTINCT WAYS ARE THERE TO CLIMB n STAIRS TAKING 1 OR 2 AT A TIME?

recurrence relationbase casecount-the-ways DP
WHAT TO WATCH FOR
  • 01THE TELL FOR A DP PROBLEM: COUNT ALL WAYS, OR FIND THE MIN / MAX
  • 02THE BASE CASE RETURNS 1, NOT 0. HE POINTS BACK AT RECURSION LECTURE 7
  • 03THE ANSWER IS FIBONACCI, AND HE DOES NOT PRETEND OTHERWISE
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
16 / VIDEO UNIT 02 · 1D RECURRENCE

DP 2 · Climbing Stairs

STRIVER A2Z
Recognising a DP problem · writing f(i) from the moves · why the base case is 1
RUNTIME 13:17
AFTER THIS → 3 DRILLS · PROBLEM #02
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
17 / DRILL UNIT 02 · 1D RECURRENCE · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Climbing Stairs counts ways rather than optimising. What does the base case return, and why?

The lecture stops and points back at recursion lecture 7 for this exact reason. When you are counting ways, arriving at the target is itself one valid way, so the base case contributes a 1 that gets summed up the tree. Return 0 and every count collapses to zero.

DRILL 02 · RECALL

The lecture gives the tell for spotting a DP problem in the statement. Which phrasing is it?

Count-all-ways and find-the-min-or-max are the two shapes that mean 'try every option, then combine', which is recursion, which becomes DP once the subproblems repeat. This is the recognition skill the SIGNALS slide is built from.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
18 / DRILL UNIT 02 · 1D RECURRENCE · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · TRACE

n = 4, and you may climb 1 or 2 steps. Step the table. What is dp[4]?

dp[0]=1, dp[1]=1, then each cell is the sum of the two below it: dp[2]=2, dp[3]=3, dp[4]=5. It is Fibonacci wearing a different problem statement, which is the point of putting this lecture second.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
19 / MECHANISM UNIT 02 · FILLCOUNT · CODE MIRRORED

THE FIRST TABLE, COUNTING WAYS

Climbing stairs, n = 8. Every cell is the sum of the two below it, and the base case is a 1 because arriving is itself one way. Step it and watch the two cells each new answer reads. That pair is the entire reason this collapses to two variables later.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
20 / PROBLEM #02 · 1D · MED

Climbing stairs

MED 1d ▶ SOLVE ON LEETCODESheet says MEDIUM, LeetCode says Easy. The sheet's label wins per PLAN §6.1, and it is defensible: the row is the first place a recurrence has to be WRITTEN, not recognised.
SIGNAL — WHAT GIVES IT AWAY

“In how many distinct ways” plus a small set of moves. Counting, not optimising, so the children get ADDED, and the base case contributes a 1.

INTUITION

To be standing on stair i you arrived from i−1 or from i−2, and those two sets of routes are disjoint. So the count at i is the sum of the counts below it. The base case is 1 because arriving is itself one complete way. Return 0 and every count collapses.

STEPS
  1. State: f(i) = number of ways to reach stair i.
  2. Transition: f(i) = f(i−1) + f(i−2). The two stairs you could have come from.
  3. Base: f(0) = 1 (standing still is one way) and f(1) = 1.
  4. Tabulate left to right, then keep only the last two values.
BRUTEO(2ⁿ)
OPTIMALO(n)
↕ SCROLL
int climbStairs(int n) {
    int prev2 = 1, prev1 = 1;          // dp[0] = dp[1] = 1
    for (int i = 2; i <= n; i++) {
        int cur = prev1 + prev2;       // one step below, or two
        prev2 = prev1;
        prev1 = cur;
    }
    return prev1;
}
TIMEO(n)one pass
SPACEO(1)two variables
TRAP

Returning 0 at the base case, out of habit from optimisation problems. In a COUNT, reaching the target is one way and must contribute 1. Every answer becomes 0 and it looks like the recurrence is wrong when the base case is.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
21 / INTRO UNIT 03 · COST ON THE JUMP

UNIT 03 — COST ON THE JUMP

When the transition carries a cost rather than a count

THE QUESTION THIS LECTURE ANSWERS

THE FROG PAYS |h[i] − h[j]| TO JUMP. WHAT IS THE CHEAPEST WAY DOWN THE ARRAY?

cost on the transitionguard conditionINT_MAX as +∞
WHAT TO WATCH FOR
  • 01THE BASE CASE IS NOW 0, NOT 1. THE QUANTITY CHANGED, SO THE BASE CASE DID
  • 02“YOU CAN DO INDEX MINUS TWO IF IT IS NOT THE FIRST INDEX”
  • 03THE ILLEGAL JUMP IS INITIALISED HUGE, NEVER 0. OTHERWISE min PICKS IT
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
22 / VIDEO UNIT 03 · COST ON THE JUMP

DP 3 · Frog Jump

STRIVER A2Z
Cost on the edge · min instead of sum · guarding the two-step jump
RUNTIME 38:50
AFTER THIS → 3 DRILLS · PROBLEM #03
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
23 / DRILL UNIT 03 · COST ON THE JUMP · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Frog Jump swaps counting for optimising. What does its base case at index 0 return?

The frog starts at index 0, so standing there has cost nothing. Returning 1 here (the Climbing Stairs reflex) poisons every path with a phantom unit of energy. The base case follows the QUANTITY being computed, not the shape of the recursion.

DRILL 02 · BUG

The two-jump branch of Frog Jump. One line is wrong. Which one?

int f(int i, vector<int>& h, vector<int>& dp){
    if(i == 0) return 0;
    if(dp[i] != -1) return dp[i];
    int one = f(i-1,h,dp) + abs(h[i]-h[i-1]);
    int two = f(i-2,h,dp) + abs(h[i]-h[i-2]);
    return dp[i] = min(one, two);
}

At i == 1 the two-step jump reads h[-1] and recurses into f(-1). The lecture guards it explicitly: the second jump is only legal when i > 1. The fix is int two = INT_MAX; if(i > 1) two = ..., INT_MAX rather than 0, so an illegal jump can never win the min.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
24 / DRILL UNIT 03 · COST ON THE JUMP · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

When you guard the illegal two-step jump, what should the unused branch be initialised to?

This is a min problem, so a disallowed option must be made unattractive, not cheap. Initialise it to 0 and the min will pick the jump that never happened. The mirror of this trap returns at Minimum Path Sum, where an out-of-grid cell has to return a huge value for the same reason.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
25 / PROBLEM #03 · 1D · MED

Frog Jump

MED 1d SOLVE ON GEEKSFORGEEKS
SIGNAL — WHAT GIVES IT AWAY

A cost attached to the MOVE rather than to the cell, and “minimum total energy”. Optimisation, so the children get min-ed and the base case is 0.

INTUITION

Standing on stone i, you got there from i−1 or i−2 and paid the height difference. So the cheapest way to i is the cheaper of those two arrivals plus its jump cost. The frog starts on stone 0 having spent nothing, which is why this base case is 0 and the stairs one was 1.

STEPS
  1. State: f(i) = minimum energy to reach stone i.
  2. Transition: min(f(i−1) + |h[i]−h[i−1]|, f(i−2) + |h[i]−h[i−2]|).
  3. Guard the second branch. It only exists when i > 1.
  4. Initialise the unavailable branch to +∞, never 0.
  5. Base: f(0) = 0. Tabulate, then keep two variables.
BRUTEO(2ⁿ)
OPTIMALO(n)
↕ SCROLL
int frogJump(vector<int>& h) {
    int n = h.size();
    int prev2 = 0, prev1 = 0;          // dp[0] = 0: no energy spent yet
    for (int i = 1; i < n; i++) {
        int one = prev1 + abs(h[i] - h[i-1]);
        int two = INT_MAX;             // NOT 0 - an illegal jump must never win
        if (i > 1) two = prev2 + abs(h[i] - h[i-2]);
        int cur = min(one, two);
        prev2 = prev1;
        prev1 = cur;
    }
    return prev1;
}
TIMEO(n)one pass
SPACEO(1)two variables
TRAP

Initialising the illegal two-step jump to 0 instead of INT_MAX. The min then always picks the jump that could not be made, and the answer comes out too small, a plausible number from code that reads correctly.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
26 / INTRO UNIT 04 · K TRANSITIONS

UNIT 04 — K TRANSITIONS

Generalising a fixed branching factor to a loop over k

THE QUESTION THIS LECTURE ANSWERS

THE FROG MAY NOW JUMP UP TO k STEPS. WHAT CHANGES, AND WHAT DOES IT COST?

branching factorloop transitionreach of a recurrence
WHAT TO WATCH FOR
  • 01THE TWO HARD-CODED BRANCHES BECOME ONE LOOP, NOTHING ELSE MOVES
  • 02i − j MUST STAY ≥ 0, AND HE BREAKS OUT WHEN IT WOULD NOT
  • 03THE TIME GOES O(n) → O(n·k), AND THE SPACE CAN NO LONGER BE TWO VARIABLES
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
27 / VIDEO UNIT 04 · K TRANSITIONS

DP 4 · Frog Jump with K Distance

STRIVER A2Z
Two branches become a loop · the i−j ≥ 0 guard · why O(1) space stops being possible
RUNTIME 17:35
AFTER THIS → 2 DRILLS · PROBLEM #04
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
28 / DRILL UNIT 04 · K TRANSITIONS

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Frog Jump with K distances replaces two hard-coded branches with a loop over j = 1..k. What must be checked inside that loop?

With k arbitrary, the loop will happily walk past the start of the array. The lecture stops on this: i-j must stay >= 0, and once it would not, you break out. It is the same guard as lecture 3, generalised, which is exactly why this lecture is short.

DRILL 02 · RECALL

Frog Jump (k=2) space-optimises to two variables. Why can't Frog Jump with K distances?

prev/prev2 works only when the recurrence reaches back a fixed, tiny distance. Here it reaches back up to k, so you need the last k values live, which for large k is the whole array. This is the concrete case that makes unit 1's fourth drill real rather than theoretical.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
29 / PROBLEM #04 · 1D · MED

Frog jump with K distances

MED 1d SOLVE ON GEEKSFORGEEKSThe same problem as #03 with the fixed 2 replaced by k. It is NOT shown as a diff: #03 ships space-optimised to two variables, and this one cannot be, reaching k cells back forces the whole row to stay alive. That difference is the point, so both listings are given in full.
SIGNAL — WHAT GIVES IT AWAY

The same statement as the previous row with the fixed 2 replaced by a parameter k. A fixed branching factor becoming a variable one always means a loop.

INTUITION

Nothing conceptual changes. Where there were two candidate predecessors there are now up to k, so the two hand-written branches become a loop over j = 1..k with the same guard applied once instead of twice. What DOES change is the space: the recurrence now reaches k cells back, so the row has to stay alive.

STEPS
  1. State is unchanged: f(i) = minimum energy to reach stone i.
  2. Loop j from 1 to k, skipping any j where i − j < 0.
  3. Take the min of f(i−j) + |h[i]−h[i−j]| over the legal j.
  4. Keep the whole dp array, two variables no longer suffice.
BRUTEO(kⁿ)
OPTIMALO(n·k)
↕ SCROLL
int frogJumpK(vector<int>& h, int k) {
    int n = h.size();
    vector<int> dp(n, 0);              // the whole row must stay alive now
    for (int i = 1; i < n; i++) {
        int best = INT_MAX;
        for (int j = 1; j <= k; j++) {
            if (i - j < 0) break;      // the guard: never a negative index
            best = min(best, dp[i-j] + abs(h[i] - h[i-j]));
        }
        dp[i] = best;
    }
    return dp[n-1];
}
TIMEO(n·k)k candidates per index
SPACEO(n)the reach is k, so the row must stay
TRAP

Assuming the space optimisation from the previous problem still applies. It does not, and the reason is worth internalising: space optimisation is a property of how far the RECURRENCE REACHES, not of the problem it came from.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
30 / INTRO UNIT 05 · PICK / NOT-PICK

UNIT 05 — PICK / NOT-PICK

The subsequence recurrence, and why adjacency forbids i−1

THE QUESTION THIS LECTURE ANSWERS

PICK NUMBERS WITH NO TWO ADJACENT. WHAT IS THE LARGEST SUM YOU CAN MAKE?

subsequencepick / not-pickadjacency constraint
WHAT TO WATCH FOR
  • 01PICK GOES TO i−2, NOT-PICK GOES TO i−1. THAT ASYMMETRY IS THE PROBLEM
  • 02HE SENDS YOU BACK TO RECURSION LECTURES 6 AND 7 BEFORE STARTING
  • 03THE NEGATIVE INDEX WARNING, PICKING AT i = 1 REACHES f(−1)
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
31 / VIDEO UNIT 05 · PICK / NOT-PICK

DP 5 · Maximum Sum of Non-Adjacent Elements

STRIVER A2Z
Pick / not-pick · why picking i sends you to i−2 · the negative-index edge case
RUNTIME 32:23
AFTER THIS → 3 DRILLS · PROBLEM #05
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
32 / DRILL UNIT 05 · PICK / NOT-PICK · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The lecture calls this the pick / not-pick pattern. When you PICK index i, which index does the recursion go to?

Picking i forbids i-1 by the adjacency rule, so the next legal choice is i-2. Not picking sends you to i-1. That asymmetry IS the problem. Get it backwards and you have written plain maximum-subarray.

DRILL 02 · BUG

Maximum sum of non-adjacent elements. One line steps out of bounds. Which one?

int f(int i, vector<int>& a, vector<int>& dp){
    if(i == 0) return a[0];
    if(i < 0)  return 0;
    if(dp[i] != -1) return dp[i];
    int pick    = a[i] + f(i-2, a, dp);
    int notPick = 0    + f(i-1, a, dp);
    return dp[i] = max(pick, notPick);
}

Not out of bounds in the array, out of bounds in the DP TABLE. At i == 1, f(-1) is reached and dp[i] on the way back writes dp[-1]. The i<0 guard on line 3 catches the read but the lecture warns about the index itself: 'what if index was 1 and you did 1 minus 2 and you went on to a negative index'. Order the two base cases i<0 first, or clamp the call.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
33 / DRILL UNIT 05 · PICK / NOT-PICK · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · TRACE

a = [2, 7, 9, 3, 1]. Fill the table left to right. What is the answer?

dp[0]=2, dp[1]=max(7,2)=7, dp[2]=max(9+2,7)=11, dp[3]=max(3+7,11)=11, dp[4]=max(1+11,11)=12. Picking 2, 9 and 1 gives 12. The tempting 7+3 line is a trap the table kills for you.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
34 / MECHANISM UNIT 05 · FILLPICK · CODE MIRRORED

SAME LINE, DIFFERENT REACH. PICK / NOT-PICK

[2, 7, 9, 3, 1], no two adjacent. One row again, but now PICK reaches back to i-2 and NOT-PICK to i-1. The greedy answer. Take 7 and 3. loses, and you can watch the table refuse it.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
35 / PROBLEM #05 · 1D · MED

Maximum sum of non adjacent elements

MED 1d ▶ SOLVE ON LEETCODEThe sheet names the abstract form; LeetCode ships it as House Robber. Same recurrence. Note the sheet's NEXT row is called 'House robber' and is LeetCode's House Robber II. The naming is off by one and is the sheet's, not a transcription slip.
SIGNAL — WHAT GIVES IT AWAY

“No two adjacent” over a linear array, maximising a sum. The moment a choice here forbids a choice next door, you are in pick / not-pick.

INTUITION

At each element you either take it, which forbids its neighbour, so you continue from i−2, or you skip it and continue from i−1. That asymmetry is the entire problem. Carried forward as two running values, ‘best having just taken’ and ‘best having just skipped’, it is a single pass.

STEPS
  1. State: f(i) = best sum from the first i elements.
  2. Transition: f(i) = max(a[i] + f(i−2), f(i−1)).
  3. Base: f(0) = a[0]; guard f(i−2) when i = 1.
  4. Space-optimise to two rolling values.
BRUTEO(2ⁿ)
OPTIMALO(n)
↕ SCROLL
int rob(vector<int>& a) {
    int take = 0, skip = 0;            // best ending here having taken / skipped
    for (int x : a) {
        int newTake = skip + x;        // taking x forbids the previous element
        skip = max(skip, take);        // skipping x keeps the better of the two
        take = newTake;
    }
    return max(take, skip);
}
TIMEO(n)one pass
SPACEO(1)two rolling values
TRAP

Reaching a negative index. At i = 1, picking sends you to f(−1), and in the memoized version it also WRITES dp[−1] on the way back. Order the base cases so i < 0 is caught before anything indexes the table.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
36 / INTRO UNIT 06 · CIRCULAR ARRAYS

UNIT 06 — CIRCULAR ARRAYS

Breaking a circular constraint into two linear runs

THE QUESTION THIS LECTURE ANSWERS

THE HOUSES ARE IN A CIRCLE, SO THE FIRST AND LAST ARE NEIGHBOURS. NOW WHAT?

circular arrayreductionexclude-one-end trick
WHAT TO WATCH FOR
  • 01HE DOES NOT WRITE A NEW RECURRENCE. HE CALLS THE PREVIOUS ONE TWICE
  • 02THE WORD NON-NEGATIVE IN THE CONSTRAINTS, WHICH HE FLAGS AS IMPORTANT
  • 03WATCH WHAT HAPPENS WITH A SINGLE HOUSE. THE REDUCTION NEEDS A GUARD
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
37 / VIDEO UNIT 06 · CIRCULAR ARRAYS

DP 6 · House Robber 2

STRIVER A2Z
Reduction rather than a new recurrence · exclude-first and exclude-last · n = 1
RUNTIME 9:50
AFTER THIS → 3 DRILLS · PROBLEM #06
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
38 / DRILL UNIT 06 · CIRCULAR ARRAYS · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

House robber II is the circular version. How does the lecture reduce it to a problem already solved?

First and last are adjacent on a circle, so they can never both be taken. Excluding one or the other covers every legal case, and each half is exactly the previous lecture's function. This is the deck's clearest example of reduction rather than a new recurrence.

DRILL 02 · RECALL

The lecture stops on one word in the constraints and calls it 'very important'. Which?

Non-negative values are what make 'rob nothing' a safe floor of 0 and let the not-pick branch contribute a plain 0. Allow negatives and the whole framing shifts. Reading the constraints for this kind of word is the habit the CONSTRAINTS slide is built to teach.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
39 / DRILL UNIT 06 · CIRCULAR ARRAYS · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · TRANSFER

n = 1. A single house on a circle. What does the two-run reduction do, and is it right?

Excluding the first leaves nothing; excluding the last leaves nothing; max(0,0)=0 while the answer is a[0]. The reduction is sound for n>=2 and needs an explicit n==1 guard. The lecture handles it in code almost in passing, which is exactly why it is worth a drill.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
40 / PROBLEM #06 · 1D · MED

House robber

MED 1d ▶ SOLVE ON LEETCODESheet title 'House robber'; the actual problem is LeetCode 213, House Robber II. See the note on row 5.
SIGNAL — WHAT GIVES IT AWAY

The previous problem with the array bent into a circle, so the first and last elements are now neighbours. A circular constraint over a solved linear problem is almost always two linear runs.

INTUITION

On a circle the first and last houses can never both be taken. So every valid answer either leaves out the first or leaves out the last, and each of those is exactly the linear problem you already solved. Run it twice and take the better. No new recurrence is written at all.

STEPS
  1. Guard n = 1. With one house both slices are empty and the reduction returns 0.
  2. Run the linear solver on a[0 … n−2] (drop the last house).
  3. Run it again on a[1 … n−1] (drop the first house).
  4. Return the maximum of the two.
BRUTEO(2ⁿ)
OPTIMALO(n)
↕ SCROLL
int robLinear(vector<int>& a, int lo, int hi) {
    int take = 0, skip = 0;
    for (int i = lo; i <= hi; i++) {
        int newTake = skip + a[i];
        skip = max(skip, take);
        take = newTake;
    }
    return max(take, skip);
}
int rob(vector<int>& a) {
    int n = a.size();
    if (n == 1) return a[0];           // the circle degenerates - guard it
    return max(robLinear(a, 0, n-2),   // drop the last house
               robLinear(a, 1, n-1));  // drop the first house
}
TIMEO(n)two linear passes
SPACEO(1)two rolling values each
TRAP

Forgetting the single-house case. Both slices come out empty, max(0, 0) is 0, and the answer should have been a[0]. The reduction is sound for n ≥ 2 and silently wrong for n = 1.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
41 / INTRO UNIT 07 · THE 2D TURN

UNIT 07 — THE 2D TURN

A second changing parameter, and why it becomes a second dimension

THE QUESTION THIS LECTURE ANSWERS

EACH DAY PICK ONE OF THREE TASKS, NEVER THE SAME AS YESTERDAY. MAXIMISE MERIT.

statedimensionconstraint-carrying index
WHAT TO WATCH FOR
  • 01THE THREE STEPS: EXPRESS IN TERMS OF AN INDEX · DO ALL STUFFS · TAKE MAX/MIN
  • 02“TELL THE PREVIOUS DAY THAT YOU PERFORMED THE ith TASK, SO DO NOT PERFORM IT”
  • 03THE SECOND INDEX IS NOT THE ARRAY BEING 2D. IT IS THE CONSTRAINT NEEDING MEMORY
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
42 / VIDEO UNIT 07 · THE 2D TURN

DP 7 · Ninja's Training

STRIVER A2Z
The three steps for any recurrence · why the state carries yesterday's choice
RUNTIME 52:18
AFTER THIS → 3 DRILLS · PROBLEM #07
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
43 / DRILL UNIT 07 · THE 2D TURN · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

This lecture states the three steps for writing ANY DP recurrence. What is step one?

Express in terms of index -> do all possible stuffs on that index -> take max or min or sum per the question. The lecture calls this out as the reusable method, and it is the sentence the whole deck is organised around. It is why unit 7 is titled THE 2D TURN rather than 'Ninja's Training'.

DRILL 02 · RECALL

Why does Ninja's Training need a SECOND dimension when the 1D problems did not?

The day alone does not determine the subproblem. You also need to know which task was done last, because it is forbidden today. A parameter that changes AND affects the answer is a dimension. That test is the whole content of this lecture and it generalises to every 2D DP after it.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
44 / DRILL UNIT 07 · THE 2D TURN · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · BUG

Ninja's Training, top-down. One line quietly allows an illegal schedule. Which one?

int f(int day, int last, vector<vector<int>>& p, vector<vector<int>>& dp){
    if(day == 0){
        int mx = 0;
        for(int t = 0; t < 3; t++)
            if(t != last) mx = max(mx, p[0][t]);
        return mx;
    }
    if(dp[day][last] != -1) return dp[day][last];
    int mx = 0;
    for(int t = 0; t < 3; t++)
        mx = max(mx, p[day][t] + f(day-1, t, p, dp));
    return dp[day][last] = mx;
}

The base case correctly skips t == last, but the recursive loop forgot to. It lets the ninja repeat yesterday's task, and because the value can only go up, the bug always inflates the answer rather than crashing. Wrong output that looks plausible is exactly what the TRAPS slide is reserved for.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
45 / MECHANISM UNIT 07 · GRID2D · CODE MIRRORED

THE SECOND DIMENSION APPEARS

Ninja's Training. The day alone does not determine the answer: yesterday's task is forbidden today, so the state has to carry it. Rows are days, columns are which task was done last, and that second axis is what a second dimension actually is.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
46 / PROBLEM #07 · GRIDS · MED

Ninja's training

MED grids SOLVE ON GEEKSFORGEEKS
SIGNAL — WHAT GIVES IT AWAY

A choice per day, and today's choice constrained by yesterday's. The instant a past decision affects a future one, the state has to carry it.

INTUITION

The day alone does not determine the subproblem. You also need to know which task was done last, because it is forbidden now. A parameter that changes AND affects the answer is a dimension, so the table becomes dp[day][last]. That test is the whole content of this problem and it generalises to every 2D DP after it.

STEPS
  1. State: f(day, last) = best merit from day 0 to `day`, given `last` is banned today.
  2. Transition: for each task t ≠ last, p[day][t] + f(day−1, t); take the max.
  3. Base: on day 0, the best is the best task that is not `last`.
  4. Tabulate day by day, keeping only the previous day's three values.
BRUTEO(3ⁿ)
OPTIMALO(n·9)
↕ SCROLL
int ninjaTraining(vector<vector<int>>& p) {
    int n = p.size();
    vector<int> prev(3);
    for (int t = 0; t < 3; t++) prev[t] = p[0][t];
    for (int day = 1; day < n; day++) {
        vector<int> cur(3);
        for (int last = 0; last < 3; last++) {
            int best = 0;
            for (int t = 0; t < 3; t++)
                if (t != last) best = max(best, prev[t]);  // t != last, EVERY loop
            cur[last] = p[day][last] + best;
        }
        prev = cur;
    }
    return max({prev[0], prev[1], prev[2]});
}
TIMEO(n·9)3 tasks × 3 previous per day
SPACEO(1)one row of three values
TRAP

Putting the t != last guard in the base case and forgetting it in the recursive loop. The ninja repeats yesterday's task, the total can only go UP, and the answer is plausibly too big rather than obviously broken.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
47 / INTRO UNIT 08 · DP ON GRIDS

UNIT 08 — DP ON GRIDS

Counting paths on a grid, and all four forms of the same answer

THE QUESTION THIS LECTURE ANSWERS

HOW MANY WAYS ARE THERE FROM THE TOP-LEFT TO THE BOTTOM-RIGHT, RIGHT AND DOWN ONLY?

path lengthbackward recursioncombinatorial check
WHAT TO WATCH FOR
  • 01HE DERIVES THE PATH LENGTH (m−1)+(n−1) BEFORE WRITING ANYTHING
  • 02THE RECURSION RUNS BACKWARDS FROM THE DESTINATION, SO UP IS i−1 AND LEFT IS j−1
  • 03THE FIRST ROW AND COLUMN COME OUT ALL 1s. ONE WAY TO WALK A STRAIGHT LINE
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
48 / VIDEO UNIT 08 · DP ON GRIDS

DP 8 · Grid Unique Paths

STRIVER A2Z
Path length before code · the recursion written backwards · all four forms
RUNTIME 48:29
AFTER THIS → 3 DRILLS · PROBLEM #08
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
49 / DRILL UNIT 08 · DP ON GRIDS · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

For an m x n grid moving only right and down, the lecture derives the path LENGTH before writing any code. What is it?

Every path takes exactly m-1 downs and n-1 rights in some order, which is also why the closed-form answer is a binomial coefficient. Knowing the path length is what lets you sanity-check a table before trusting it.

DRILL 02 · RECALL

Walking BACKWARD from (m-1, n-1), the recursion at cell (i, j) calls which two cells?

The lecture writes the recursion in reverse (from destination to origin), so a step 'up' is i-1 and a step 'left' is j-1. It matters because the base case then sits at (0,0) returning 1, and every guard is i > 0 / j > 0 rather than a bounds check against m and n.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
50 / DRILL UNIT 08 · DP ON GRIDS · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · TRACE

A 3 x 3 grid, moving only right and down. Fill it. How many unique paths?

Row and column of 1s, then each interior cell is up + left: the last cell is 6. Check it against the path-length rule, 2 downs and 2 rights, choose 2 from 4, which is 6. Two independent derivations agreeing is how you trust a table.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
51 / MECHANISM UNIT 08 · GRIDPATHS · CODE MIRRORED

COUNTING ON A RECTANGLE

A 3 × 3 grid, moving only right and down. Same recurrence shape as the stairs. each cell sums the two it can be reached from, but the two are now up and left. The first row and column are all 1s because there is exactly one way to walk a straight line.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
52 / PROBLEM #08 · GRIDS · MED

Grid Unique Paths : DP on Grids (DP8)

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

A grid, movement restricted to right and down, and “how many unique paths”. Counting on a rectangle. The table has the grid's own shape.

INTUITION

Each cell can only be entered from above or from the left, and those two sets of routes are disjoint, so its count is their sum. Walking the recursion backwards from the destination makes the base case (0,0) return 1 and turns every bound into a simple i > 0 / j > 0 test.

STEPS
  1. Sanity check first: every path is (m−1) downs and (n−1) rights, so the answer is C(m+n−2, m−1). Use it to check the table.
  2. State: f(i,j) = number of ways to reach (i,j).
  3. Transition: f(i,j) = f(i−1,j) + f(i,j−1), with off-grid contributing 0.
  4. Base: f(0,0) = 1. First row and column fill with 1s.
  5. Keep one row rather than the whole table.
BRUTEO(2^(m+n))
OPTIMALO(n·m)
↕ SCROLL
int uniquePaths(int m, int n) {
    vector<int> prev(n, 0);
    for (int i = 0; i < m; i++) {
        vector<int> cur(n, 0);
        for (int j = 0; j < n; j++) {
            if (i == 0 && j == 0) { cur[j] = 1; continue; }   // one way to stand still
            cur[j] = (j ? cur[j-1] : 0)        // left, 0 if off-grid
                   + (i ? prev[j]   : 0);      // up,   0 if off-grid
        }
        prev = cur;
    }
    return prev[n-1];
}
TIMEO(n·m)every cell filled once
SPACEO(m)one live row
TRAP

On a counting problem the off-grid return is 0, and that is right here. Carry the habit into the next problem, where the combine is a min, and the illegal route becomes the cheapest one. The identity belongs to the OPERATOR.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
53 / INTRO UNIT 09 · OBSTACLES

UNIT 09 — OBSTACLES

One guard clause turns a count into a constrained count

THE QUESTION THIS LECTURE ANSWERS

THE SAME GRID, BUT SOME CELLS ARE BLOCKED. HOW MUCH OF THE CODE CHANGES?

obstacleguard clause1e9+7
WHAT TO WATCH FOR
  • 01“IT IS JUST A SINGLE LINE ADDITION”, AND HE MEANS IT LITERALLY
  • 02AN OBSTACLE RETURNS 0: IT CONTRIBUTES NO PATHS, SO THE SUM ABOVE IT DOES THE REST
  • 03HE STOPS THE WALKTHROUGH TO DECLARE THE MODULUS, WHICH IS NOT A DP IDEA AT ALL
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
54 / VIDEO UNIT 09 · OBSTACLES

DP 9 · Unique Paths II

STRIVER A2Z
The obstacle guard · base-case ordering · the modulus everyone forgets
RUNTIME 12:59
AFTER THIS → 3 DRILLS · PROBLEM #09
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
55 / DRILL UNIT 09 · OBSTACLES · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Unique Paths II adds obstacles. What is the entire change to the recursion?

An obstacle cell contributes no paths, so it returns 0 and the sum above it does the rest. The lecture is blunt that this is a single-line addition to lecture 8, which is why the deck ships it as a code diff rather than a fresh derivation.

DRILL 02 · RECALL

The lecture flags one thing that has nothing to do with obstacles and will still fail you. What?

Path counts blow past 32-bit fast, and the judge asks for the count mod 1e9+7. The lecture stops the code walkthrough to declare the modulus globally. It is not a DP idea at all, which is precisely why it gets forgotten.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
56 / DRILL UNIT 09 · OBSTACLES · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · BUG

Unique Paths II. One line puts the guard in the wrong place. Which one?

int f(int i, int j, vector<vector<int>>& g, vector<vector<int>>& dp){
    if(i >= 0 && j >= 0 && g[i][j] == 1) return 0;
    if(i == 0 && j == 0) return 1;
    if(i < 0 || j < 0) return 0;
    if(dp[i][j] != -1) return dp[i][j];
    int up   = f(i-1, j, g, dp);
    int left = f(i, j-1, g, dp);
    return dp[i][j] = (up + left) % MOD;
}

The obstacle check runs before the out-of-bounds check, so it has to re-test i and j itself, and if you ever drop that half of the condition, g[-1][j] reads off the end. The lecture's ordering is out-of-bounds first, then obstacle, then destination. Cheap to get right, silent when wrong.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
57 / PROBLEM #09 · GRIDS · MED

Unique paths II

MED grids ▶ SOLVE ON LEETCODEProblem 8 with one guard clause for obstacles. Ships as a code diff against 8.
SIGNAL — WHAT GIVES IT AWAY

The previous grid with some cells blocked. A constraint layered on a solved counting problem is usually one guard, not a new method.

INTUITION

A blocked cell can be part of no path, so it contributes 0, and the sum above and to the left of it does the rest automatically. Nothing else changes. What is easy to get wrong is not the DP but the ORDER of the base cases, and the modulus the judge asks for.

STEPS
  1. Check the obstacle AFTER the bounds check and BEFORE the destination check.
  2. A blocked cell sets dp to 0 and continues.
  3. Everything else is problem #08 unchanged.
  4. Take the result modulo 1e9+7. Path counts overflow 32 bits quickly.
BRUTEO(2^(m+n))
OPTIMALO(n·m)
-int uniquePaths(int m, int n) {+int uniquePathsWithObstacles(vector<vector<int>>& g) {+    int m = g.size(), n = g[0].size();     vector<int> prev(n, 0);     for (int i = 0; i < m; i++) {         vector<int> cur(n, 0);         for (int j = 0; j < n; j++) {-            if (i == 0 && j == 0) { cur[j] = 1; continue; }   // one way to stand still-            cur[j] = (j ? cur[j-1] : 0)        // left, 0 if off-grid-                   + (i ? prev[j]   : 0);      // up,   0 if off-grid+            if (g[i][j] == 1) { cur[j] = 0; continue; }   // blocked: no paths+            if (i == 0 && j == 0) { cur[j] = 1; continue; }+            cur[j] = (j ? cur[j-1] : 0) + (i ? prev[j] : 0);         }         prev = cur;     }     return prev[n-1]; }
TIMEO(n·m)every cell filled once
SPACEO(m)one live row
TRAP

Testing g[i][j] == 1 before testing whether i and j are in range. It reads off the end of the grid, and because the read usually lands on live memory it does not crash. It returns a wrong count on some inputs and the right one on others.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
58 / INTRO UNIT 10 · COUNT TO OPTIMISE

UNIT 10 — COUNT TO OPTIMISE

Swapping the sum for a min turns a path count into a path optimisation

THE QUESTION THIS LECTURE ANSWERS

SAME WALK, BUT EACH CELL COSTS SOMETHING. WHAT IS THE CHEAPEST ROUTE ACROSS?

identity element+∞ sentinelcount vs optimise
WHAT TO WATCH FOR
  • 01“THIS HAS TO RETURN SOMETHING SUCH THAT THIS PATH IS NOT CONSIDERED”
  • 02THE REQUIREMENT COMES BEFORE THE VALUE. HE SAYS WHAT IT MUST DO, THEN PICKS 1e9
  • 03NOTHING ELSE MOVES: SAME LOOP, SAME INDICES, ONE OPERATOR
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
59 / VIDEO UNIT 10 · COUNT TO OPTIMISE

DP 10 · Minimum Path Sum in Grid

STRIVER A2Z
Counting becomes optimising · what an out-of-grid cell must return, and why
RUNTIME 23:47
AFTER THIS → 3 DRILLS · CONCEPT UNIT
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
60 / DRILL UNIT 10 · COUNT TO OPTIMISE · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Minimum Path Sum turns counting into optimising. What must an out-of-grid cell return now?

The lecture states the requirement before the value: the return must be something that makes this path 'not considered'. In a min, that is a huge number. Return 0 (the answer that was correct when counting), and every illegal path becomes the cheapest one.

DRILL 02 · RECALL

Same grid, same recursion, but Unique Paths returns 0 out of bounds and Minimum Path Sum returns 1e9. What decides?

An out-of-range return is the identity for whatever operation combines the children. For a sum that is 0; for a min it is +infinity; for a max it is -infinity. Learn it as the identity and you never have to memorise it per problem again.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
61 / DRILL UNIT 10 · COUNT TO OPTIMISE · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · TRANSFER

This unit has no row on Striver's sheet. Why is it still in the deck?

Triangle, Falling Path Sum and Cherry Pickup II are all minimise-or-maximise problems, and this is where that turn is explained. The sheet skips it; skipping it in the deck would leave the next three units resting on an argument nobody made. It owns no problem slide precisely because it owns no sheet row.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
62 / MECHANISM UNIT 10 · GRIDMIN · CODE MIRRORED

THE HINGE, COUNTING BECOMES OPTIMISING

Identical walk, identical table, one operator changed: the sum becomes a min and each cell adds its own cost. This is the turn every grid problem after it depends on, and it is also where an out-of-grid cell stops returning 0 and starts returning infinity.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
63 / INTRO UNIT 11 · FIXED START, FREE END

UNIT 11 — FIXED START, FREE END

When the start is pinned and the end is not

THE QUESTION THIS LECTURE ANSWERS

A TRIANGLE, STARTING AT THE APEX. ANY CELL OF THE LAST ROW IS A LEGAL FINISH.

variable ending pointbottom-up fillrow rolling
WHAT TO WATCH FOR
  • 01THE ANSWER IS THE BEST OVER A WHOLE ROW, NOT ONE CELL
  • 02HE ASKS WHETHER YOU CAN EVER LEAVE THE TRIANGLE GOING DOWN-RIGHT. YOU CANNOT
  • 03THE SPACE OPTIMISATION KEEPS ONE ROW: THE CURRENT BECOMES THE FRONT
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
64 / VIDEO UNIT 11 · FIXED START, FREE END

DP 11 · Triangle

STRIVER A2Z
Fixed start, variable end · why the triangle never goes out of bounds · one live row
RUNTIME 34:39
AFTER THIS → 3 DRILLS · PROBLEM #11
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
65 / DRILL UNIT 11 · FIXED START, FREE END · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Triangle is the FIXED start, VARIABLE end pattern. What does that change about the answer?

You always start at (0,0), but any cell of the last row is a legal finish, so the answer is the best over that row rather than one cell. This is the distinction the next lecture generalises, and the reason these two units sit in this order.

DRILL 02 · TRACE

Triangle [[2],[3,4],[6,5,7],[4,1,8,3]]. Fill it bottom-up. What is the minimum path sum from the apex?

Bottom row stays [4,1,8,3]. Row 2 becomes [6+min(4,1), 5+min(1,8), 7+min(8,3)] = [7,6,10]. Row 1 becomes [3+min(7,6), 4+min(6,10)] = [9,10]. Apex is 2+min(9,10) = 11, via 2->3->5->1. Doing it bottom-up is what makes the 'variable ending point' disappear. The whole last row is just the base case.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
66 / DRILL UNIT 11 · FIXED START, FREE END · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

For the space-optimised tabulation the lecture keeps a row alive. Which one?

Filling bottom-up, row i only ever reads row i+1, so one array plus a temporary is enough. 'this current row becomes the front row'. Same argument as prev/prev2 in unit 1, one dimension up.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
67 / PROBLEM #11 · GRIDS · MED

Triangle

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

A triangle, a fixed apex, and any cell of the last row a legal finish. Fixed start, variable end. The answer is one cell, but the base case is a whole row.

INTUITION

Filled bottom-up, the ‘variable ending point’ disappears entirely: the last row IS the base case, and each row above it takes the better of the two cells below. Because the shape narrows, the diagonal can never leave the triangle, so this is the one grid problem with no bounds check.

STEPS
  1. Start from the last row. Copy it into dp, and it becomes the base case.
  2. For each row above, dp[j] = t[i][j] + min(dp[j], dp[j+1]).
  3. Fill upward. The apex ends holding the answer.
  4. One array is enough, the current row overwrites the one below it.
BRUTEO(2ⁿ)
OPTIMALO(n²)
↕ SCROLL
int minimumTotal(vector<vector<int>>& t) {
    int n = t.size();
    vector<int> dp(t[n-1].begin(), t[n-1].end());  // base case IS the last row
    for (int i = n - 2; i >= 0; i--)
        for (int j = 0; j <= i; j++)
            dp[j] = t[i][j] + min(dp[j], dp[j+1]); // down, or diagonal
    return dp[0];                                  // start is fixed at the apex
}
TIMEO(n²)one cell per triangle entry
SPACEO(n)a single row, rolled
TRAP

Filling top-down and then hunting for the minimum of the last row. It works, but it needs the bounds handling the bottom-up version never has, and it obscures that the base case and the free endpoint are the same fact.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
68 / INTRO UNIT 12 · FREE START, FREE END

UNIT 12 — FREE START, FREE END

Both ends variable, the loop over every starting column

THE QUESTION THIS LECTURE ANSWERS

START AT ANY CELL OF THE FIRST ROW AND END ANYWHERE. NOW WHAT DOES THE DRIVER LOOK LIKE?

variable starting pointdriver loopthree-way transition
WHAT TO WATCH FOR
  • 01HE OPENS BY NAMING LECTURE 11. THIS IS THAT PROBLEM WITH ONE MORE FREEDOM
  • 02THE FREEDOM LIVES IN THE DRIVER, NOT IN THE STATE. THE RECURRENCE IS UNCHANGED
  • 03A RECTANGLE HAS STRAIGHT EDGES, SO THE DIAGONALS NOW NEED A BOUNDS CHECK
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
69 / VIDEO UNIT 12 · FREE START, FREE END

DP 12 · Minimum/Maximum Falling Path Sum

STRIVER A2Z
Variable start AND end · looping the driver · bounds the triangle gave you free
RUNTIME 42:38
AFTER THIS → 3 DRILLS · PROBLEM #10
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
70 / DRILL UNIT 12 · FREE START, FREE END · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

This lecture opens by naming what it generalises. What is the new freedom?

The lecture literally says so: lecture 11 did fixed start / variable end, and a commenter asked what happens when both are free. Nothing else changes, so this unit follows Triangle even though the sheet lists it first.

DRILL 02 · RECALL

A variable STARTING cell changes the top-level call. How?

With no fixed origin, every cell of the first row is a candidate start, so the driver loops over them and takes the max. The dp table is shared across those calls, which is why this costs a loop and not a factor of m.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
71 / DRILL UNIT 12 · FREE START, FREE END · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · TRACE

Matrix [[1,2,10,4],[100,3,2,1],[1,1,20,2],[1,2,2,1]], moving down / down-left / down-right, starting anywhere in row 0. What is the MAXIMUM falling path sum?

Start at 2 (row 0, col 1), take 100, then 1, then 2, for 105. The trap is starting at 10 because it is the biggest number in the first row; that path cannot reach 100 and tops out lower. A variable starting point means you loop over ALL of row 0 and let the table decide, never eyeball the best-looking start.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
72 / PROBLEM #10 · GRIDS · MED

Minimum Falling Path Sum

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

“Starting from any cell in the first row” and ending anywhere in the last. Both endpoints free, the freedom lives in the driver, not the state.

INTUITION

The recurrence is the same three-way step down that a triangle uses. What changes is that there is no single top-level call: every cell of the first row is a candidate start, and every cell of the last row a candidate finish. So the driver loops over the starts and the answer is taken over a whole row.

STEPS
  1. State: f(i,j) = best falling path sum ending at (i,j).
  2. Transition: g[i][j] + best of f(i−1, j−1), f(i−1, j), f(i−1, j+1).
  3. Bounds-check both diagonals. A rectangle, unlike a triangle, has straight edges.
  4. Base: row 0 is just its own values, since any of them may start a path.
  5. Answer: the best value anywhere in the last row.
BRUTEO(3ⁿ)
OPTIMALO(n·m)
↕ SCROLL
int minFallingPathSum(vector<vector<int>>& g) {
    int n = g.size(), m = g[0].size();
    vector<int> prev(g[0].begin(), g[0].end());   // any cell of row 0 may start
    for (int i = 1; i < n; i++) {
        vector<int> cur(m);
        for (int j = 0; j < m; j++) {
            int best = prev[j];
            if (j > 0)     best = min(best, prev[j-1]);   // bounds - a rectangle
            if (j < m - 1) best = min(best, prev[j+1]);   // has straight edges
            cur[j] = g[i][j] + best;
        }
        prev = cur;
    }
    return *min_element(prev.begin(), prev.end());        // end anywhere
}
TIMEO(n·m)three transitions per cell
SPACEO(m)one live row
TRAP

Eyeballing the biggest number in the first row and starting there. A variable starting point means you loop over ALL of row 0 and let the table decide. The best-looking start routinely leads nowhere.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
73 / INTRO UNIT 13 · 3D DP

UNIT 13 — 3D DP

Two agents moving at once, and the third dimension that tracks both

THE QUESTION THIS LECTURE ANSWERS

ALICE AND BOB BOTH WALK DOWN THE GRID. HOW MANY CHERRIES CAN THEY COLLECT TOGETHER?

multi-agent DPlockstep movement3D state
WHAT TO WATCH FOR
  • 01“MAKE SURE ALICE AND BOB MOVE TOGETHER”. SEPARATELY DOUBLE-COUNTS
  • 02THEY SHARE A ROW, SO IT IS ONE ROW INDEX AND TWO COLUMNS, NOT FOUR
  • 03“ALWAYS WRITE THE OUT-OF-BOUND BASE CASE FIRST”
  • 043 MOVES × 3 MOVES = NINE TRANSITIONS, AS A DOUBLE LOOP INSIDE THE STATE
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
74 / VIDEO UNIT 13 · 3D DP

DP 13 · Cherry Pickup II

STRIVER A2Z
Moving in lockstep · the shared cell counted once · nine transitions per state
RUNTIME 43:23
AFTER THIS → 4 DRILLS · PROBLEM #12
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
75 / DRILL UNIT 13 · 3D DP · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The lecture's single most emphasised point about Alice and Bob. What is it?

Solving separately double-counts every cell they both pass through. Moving them in lockstep (same row, two columns) is what lets a shared cell be counted once. This is the whole reason the state is 3D and the lecture calls it out as very important.

DRILL 02 · RECALL

The state is (row, colAlice, colBob), three indices for a 2D grid. Why only three and not four?

Because they step in lockstep, both are always on the same row, so the row is one shared index and only the two columns vary independently. Recognising that a fourth parameter is redundant is what keeps this O(n*m*m) instead of far worse.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
76 / DRILL UNIT 13 · 3D DP · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The lecture names two kinds of base case and insists on an order. Which comes first?

'Always write the out of bound first.' If the destination check runs first it can read a cell that is already off the grid. The same ordering bug is planted in unit 9's drill. It recurs because it is genuinely easy to get wrong.

DRILL 02 · TRANSFER

Sheet difficulty says MEDIUM; LeetCode calls Cherry Pickup II HARD. What actually makes it harder than everything before it?

Alice has 3 moves and Bob has 3, so each state branches 3 x 3 = 9 ways and the inner step is a double loop. Nothing about the METHOD is new (express in terms of index, do all stuffs, take the max), which is why the sheet is comfortable calling it Medium. The volume is what bites.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
77 / MECHANISM UNIT 13 · GRID3D · CODE MIRRORED

TWO WALKERS, ONE ROW

Alice starts top-left, Bob top-right, both step down together. They share a row, so one row index serves both and only the two columns vary, three indices for a 2D grid. Watch the row where they meet: the cherry is counted once, which is the whole reason they cannot be solved separately and added.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
78 / PROBLEM #12 · GRIDS · MED

Ninja and his Friends

MED grids ▶ SOLVE ON LEETCODESheet title 'Ninja and his Friends'; the LeetCode problem is Cherry Pickup II, 1463. The user's pasted list marked this as having no LeetCode equivalent. It does, and it is free.
SIGNAL — WHAT GIVES IT AWAY

Two agents traversing the same grid at the same time, collecting from it. Two things moving at once is never two independent problems.

INTUITION

Alice and Bob step down in lockstep, so they always share a row, one row index serves both and only the two columns vary. That shared row is what lets the transition say if a == b, count this cell once, and it is precisely the fact that solving them separately and adding would destroy.

STEPS
  1. State: f(row, colA, colB), three indices for a 2D grid, because the row is shared.
  2. Collect: g[row][a] + g[row][b], but only once when a == b.
  3. Transition: nine moves, each of Alice's three against each of Bob's three.
  4. Write the out-of-bounds base case FIRST, then the last-row case.
  5. Fill bottom-up keeping one m × m layer; the answer is f(0, 0, m−1).
BRUTEO(9ⁿ)
OPTIMALO(n·m²·9)
↕ SCROLL
int cherryPickup(vector<vector<int>>& g) {
    int n = g.size(), m = g[0].size();
    vector<vector<int>> nxt(m, vector<int>(m, 0)), cur(m, vector<int>(m, 0));
    for (int a = 0; a < m; a++)
        for (int b = 0; b < m; b++)
            nxt[a][b] = g[n-1][a] + (a == b ? 0 : g[n-1][b]);
    for (int r = n - 2; r >= 0; r--) {
        for (int a = 0; a < m; a++)
            for (int b = 0; b < m; b++) {
                int here = g[r][a] + (a == b ? 0 : g[r][b]);   // shared: ONCE
                int best = INT_MIN;
                for (int da = -1; da <= 1; da++)
                    for (int db = -1; db <= 1; db++) {         // nine moves
                        int na = a + da, nb = b + db;
                        if (na < 0 || na >= m || nb < 0 || nb >= m) continue;
                        best = max(best, nxt[na][nb]);
                    }
                cur[a][b] = here + best;
            }
        nxt = cur;
    }
    return nxt[0][m-1];                            // Alice left, Bob right
}
TIMEO(n·m²·9)nine transitions per state
SPACEO(m²)one layer of the 3D table
TRAP

Running the single-agent solution twice, once for Alice, once for Bob, and adding. Independently optimal paths cross, and every crossing gets counted twice. It gives a number that is too large and looks entirely reasonable.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
79 / RECALL RETRIEVAL, NOT RECOGNITION · 1 OF 4

NAME THE STATE FROM WHAT IS ASKED

DRILL 01 · RECALL

A grid problem asks for the number of paths. Out of bounds should return…

0, the identity for a sum. An illegal route contributes no paths. Return 1 and you invent routes that do not exist. Compare with the next question: the value is decided by the OPERATOR that combines the children, never by the problem being a grid.

DRILL 02 · RECALL

Same grid, but now it asks for the MINIMUM path sum. Out of bounds returns…

+∞, the identity for a min. Return 0 and the illegal route is the cheapest one and always wins. This is the single most common grid-DP bug and it produces a plausible small number rather than a crash, which is exactly what makes it expensive.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
80 / RECALL RETRIEVAL, NOT RECOGNITION · 2 OF 4

NAME THE STATE FROM WHAT IS ASKED

DRILL 01 · RECALL

Which of these recurrences CANNOT be space-optimised to a constant number of variables?

The one that reaches back k. Space optimisation is a property of how far the recurrence REACHES, not of the problem. Reach two cells and two variables suffice; reach k and you must keep the last k. The grid recurrence reaches one row back, so it collapses to one row, not to a constant, but still a dimension cheaper.

DRILL 02 · RECALL

You are told the answer may start at any cell of the first row. What changes?

Only the driver. The recurrence and the table are untouched; what changes is that there is no single top-level call. Loop over the legal starts, share one dp table across them, take the best. Recognising that a freedom lives in the DRIVER and not in the state is what keeps the state small.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
81 / RECALL RETRIEVAL, NOT RECOGNITION · 3 OF 4

NAME THE STATE FROM WHAT IS ASKED

DRILL 01 · RECALL

Two agents walk a grid and you want the total collected. Why can you not solve each separately and add?

Shared cells. Independently optimal paths may cross, and the sum then double-counts every crossing. Moving them together in one recursion is what lets the transition say count this cell once if a == b, and it is why the state grows a third index rather than the problem splitting in two.

DRILL 02 · TRANSFER

A statement from no lecture in this deck. Three hotels quote you a different rate for every one of the next n nights. You must stay somewhere each night and may not stay in the same hotel two nights running. Spend the least. What shape is the state?

This is the false friend, wearing different clothes. It reads like “no two adjacent”, which needs one index, but what is forbidden here has a NAME (that particular hotel), and a name does not fit in an index. The moment the forbidden thing is one of k things rather than the place you just left, the state grows a dimension: O(n·k), not O(n). The greedy option is the tempting one and it loses whenever tonight's cheapest hotel is the one that unlocks a far cheaper night tomorrow, which is why the rates have to differ per night for the question to have any teeth. That is Ninja's Training with the nouns swapped, and swapping the nouns is exactly what an interviewer does.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
82 / RECALL RETRIEVAL, NOT RECOGNITION · 4 OF 4

NAME THE STATE FROM WHAT IS ASKED

DRILL 01 · TRANSFER

Another you have not seen. n ≤ 200000 shelves stand in a row, each worth a restock bonus, and you may not restock two adjacent shelves. Collect the most. One of these is dead before you write a line of it, which, and why?

The bound killed it, not the recurrence. n ≤ 2·10⁵ buys roughly O(n log n); a table over pairs is 4·10¹⁰ cells, which is out of memory long before it is out of time. Read the constraint FIRST and it tells you how many indices you are allowed. Here, one. The other three fail for reasons you would only find later: plain recursion is exponential, and greedy loses on [5, 1, 1, 5] by taking 5 + 1 instead of 5 + 5.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
83 / TRAPS PLAUSIBLE, WRONG, AND SILENT

SIX WAYS TO BE PLAUSIBLY WRONG

None of these crash. Every one returns a number that looks like an answer, a table that is never written, a min that prefers a move nobody could make, a guard that only fires in the base case. Expense comes from exactly that.

READ THE TABLE, FORGET TO WRITE IT

if(dp[i]!=-1) return dp[i]; then return f(i-1)+f(i-2);. Every lookup misses, the answer is right, and the runtime is still exponential. Always write return dp[i] = … so storing cannot be skipped.

SIZING THE TABLE n INSTEAD OF n+1

The subproblems run 0..n inclusive, so the array needs n+1 slots. Off by one, and it is either a crash or. Worse, in release builds, a silently wrong read.

0 FOR AN ILLEGAL OPTION IN A MIN

A jump that cannot be made, or a cell off the grid, must be made UNATTRACTIVE. Return 0 and the min picks the move that never happened. Use a large value for min, a very negative one for max, the identity of the operator, not a habit.

THE GUARD ONLY IN THE BASE CASE

Ninja's Training forbids repeating yesterday's task. Put t != last in the base case and forget it in the loop and the answer only ever goes UP, a plausible number that is too big, from code that reads correctly.

OBSTACLE CHECKED BEFORE BOUNDS

if(g[i][j]==1) return 0; above the i<0 guard reads off the end of the grid. Order is always: out of bounds, then blocked, then destination.

FORGETTING THE MODULUS ON A COUNT

Path counts overflow 32 bits quickly and the judge wants the answer mod 1e9+7. Nothing about this is a DP idea, which is exactly why it is the one that gets left out.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
84 / CHEATSHEET REVISION SURFACE

ONE SCREEN, THE WHOLE DECK

The four steps, then every recurrence shape in this deck with its cost and the one line that selects it. This is the night-before page.

ALGORITHM
TIME
SPACE
REACH FOR IT WHEN
Recursion → memoization
O(2ⁿ) → O(n)
O(n) table + O(n) stack
add a table, check it on entry, WRITE it on exit
Memoization → tabulation
O(n)
O(n) table
same recurrence bottom-up in a loop, deletes the stack
Tabulation → space optimised
O(n)
O(1) or one row
only legal when the recurrence reaches back a fixed, small distance
1D · count
O(n)
O(1)
dp[i] = dp[i-1] + dp[i-2]; base case returns 1
1D · pick / not-pick
O(n)
O(1)
dp[i] = max(a[i] + dp[i-2], dp[i-1])
1D · k transitions
O(n·k)
O(n)
loop j = 1..k, guard i-j ≥ 0; cannot go O(1)
2D · extra state
O(n·k)
O(k)
dp[day][last]; skip t == last in EVERY loop
Grid · count paths
O(n·m)
O(m)
dp[i][j] = up + left; off-grid = 0; take mod
Grid · min path
O(n·m)
O(m)
dp[i][j] = g[i][j] + min(up, left); off-grid = ∞
Grid · free endpoints
O(n·m)
O(m)
loop the driver over starts; answer over a row
Grid · two walkers
O(n·m²)
O(m²)
one row index, two column indices, 9 moves
INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
85 / CLOSE STEP 16 · DECK 1 OF 4

WRITE THE RECURRENCE

Express the problem in terms of an index, do every possible thing at that index, then take the max, min or sum the question asked for. Once that recursion runs, memoize it, tabulate it, and throw the table away, and the only judgement in the whole sequence is how far back the recurrence reaches. Thirteen lectures, one line of cells that became a rectangle and then grew a third index. Deck II takes the same four steps into subsequences and knapsack, where the second index is a running SUM rather than a position.

00%
OF THIS DECK SOLVED
← ALL TOPICSTHE SHELFSTEP 07 · RECURSION

Deck 1 of 4. Lectures DP 1-13 of 56; DP 14-56 are decks II-IV. Twelve of the sheet's 55 rows. DP 10 (Minimum Path Sum) is a lecture with no sheet row and runs as a concept unit. Every drill is sourced from its lecture transcript and cites it; every bench fills in numbers the build re-derived and asserted.

INVARIANT · DYNAMIC PROGRAMMING · FOUNDATIONS · DECK 1 OF 4
■ TOO SMALL TO READ
1280×720
INVARIANT · STEP 16 · DECK 1 OF 4

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
WRITE THE RECURRENCE · THEN KILL THE RECURSION
Your progress is saved per device, so anything you tick on the laptop will be waiting there.