INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS
01
00/16
01 / COVER STEP 16 · DYNAMIC PROGRAMMING
INVARIANT · STEP 16 · DECK 3 OF 4
MATCH OR MOVE ON

Two families, one shape. On strings, the second index becomes a position in a second string: if the characters match, take them both and step back together; if not, try dropping one from each side and keep the better. On stocks, the second index becomes a flag you carry — am I holding, and how many transactions are left. Sixteen lectures, and both families are pick / not-pick with a wider state.

16Problems
3Families
16Units
5Live 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 · STRINGS & STOCKS · DECK 3 OF 4
02 / START HERE READ THIS ONE FIRST

HOW THIS DECK WORKS

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

ASSUMEDDecks I and II of this step. Every string problem here is pick / not-pick with TWO indices instead of one; every stock problem is pick / not-pick with a flag you carry. Nothing new is added to the method.

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.

16 PROBLEMS · EVERY ONE LINKS TO A JUDGE TO SOLVE

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
03 / SIGNALS WHEN YOU SEE X, REACH FOR Y

TWO STRINGS, OR ONE STRING AND A FLAG

Ten of these rows put a second STRING on the other index; six put a small carried STATE there instead. Both are pick / not-pick with a wider state, and the phrasing of the statement is what tells you which table you are about to fill.

TWO STRINGS, AND “LONGEST COMMON…”

one index per string; a match is free to take, a mismatch means try dropping either

LCS TABLE · the parent of every string row hereO(n·m)
“CONSECUTIVE” OR THE WORD “SUBSTRING”

a mismatch breaks the run, so the cell resets to 0 rather than inheriting a neighbour

SUBSTRING · answer is the largest cell, not the cornerO(n·m)
“PALINDROME” ON A SINGLE STRING

a palindrome reads the same reversed, so it is common to s and reverse(s)

REVERSE AND REUSE · LCS(s, reverse s)O(n²)
“MINIMUM INSERTIONS / DELETIONS TO CONVERT”

whatever is common survives; everything else is deleted from one side and inserted into the other

n + m − 2·LCS · arithmetic, not a new tableO(n·m)
“HOW MANY WAYS” OR A PATTERN WITH ? AND *

the transition is dictated by the characters, and a match may not be forced

MATCHING DP · add the branches, or OR themO(n·m)
PRICES, AND “AT MOST k TRANSACTIONS”

the day is the index; whether you hold, and how many trades remain, is the carried state

STOCK DP · state = (day, holding, cap)O(n·k)
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
04 / CONSTRAINTS BEFORE YOU WRITE A LINE

READ THE ANSWER OFF THE CONSTRAINTS

A pairwise string table costs n·m cells. That is the number to check first: two strings of 10³ is a million cells and fine, two of 10⁵ is 10¹⁰ and impossible — and when it is impossible the answer is not a better DP, it is a different technique.

n ≤
BUDGET
WHAT THAT BUYS YOU
n, m ≤ 10³
O(n·m)
the home row for every string problem here: one cell per pair of prefixes
n ≤ 10⁵ (one string)
O(n)
a single string with a carried flag — the stock problems, and nothing else here
n ≤ 500 with a 3rd index
O(n·m·k)
an extra dimension is affordable while the strings stay small
n, m ≤ 10⁵ both
not this table
n·m is 10¹⁰ — a pairwise table is impossible; the answer is hashing, suffix structures or a greedy argument
space
O(m)
every recurrence here reads one row back, so two rows replace the grid

The stock rows are the exception in this deck: one string, one flag, and O(n) — which is why they can take n = 10⁵ where the string rows cannot.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
05 / WARMUP BEFORE ANY OF IT · 1 OF 2

WHAT THE SECOND INDEX IS NOW

DRILL 01 · RECALL

An LCS table over strings of length n and m is built with dimensions (n+1) × (m+1). What is the extra row and column for?

Row 0 means 'no characters of a yet', and its LCS with anything is genuinely 0. So the base case IS the extra row, and the recurrence can read i−1 everywhere without a single guard. This is why the tabulated version shifts to 1-based indexing even though the strings are 0-based.

DRILL 02 · RECALL

Two characters MATCH while filling an LCS table. Why is it safe to take the pair rather than considering skipping it?

An exchange argument. Any common subsequence not using this pair can be rewritten to use it without getting shorter, so there is nothing to lose. That certainty is what makes LCS a two-branch table rather than a three-branch one — and note that Distinct Subsequences, later, is the one place it fails.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
06 / WARMUP BEFORE ANY OF IT · 2 OF 2

WHAT THE SECOND INDEX IS NOW

DRILL 01 · BUG

Edit distance. It compiles and returns a plausible number that is always too large. Which line?

int f(int i, int j, string& a, string& b, vector<vector<int>>& dp){
    if(i == 0) return j;
    if(j == 0) return i;
    if(dp[i][j] != -1) return dp[i][j];
    if(a[i-1] == b[j-1])
        return dp[i][j] = 1 + f(i-1, j-1, a, b, dp);
    return dp[i][j] = 1 + min({f(i, j-1, a, b, dp),
                               f(i-1, j, a, b, dp),
                               f(i-1, j-1, a, b, dp)});
}

A match is free. Charging 1 for it inflates the answer by exactly the length of the common subsequence — a number that scales sensibly with the input, never crashes, and looks entirely reasonable until you check a small case by hand. That is what makes it expensive.

DRILL 02 · RECALL

A stock problem tracks whether you currently hold a share. Why is that a better state than remembering the price you bought at?

State size is the whole game. A boolean gives 2n cells; a remembered price gives n² and puts a 10⁵-day problem out of reach. The profit already accounts for what you paid, so the price does not need remembering — recognising what can be dropped from a state is the skill this section drills.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
07 / ROADMAP WHAT YOU ARE ABOUT TO DO

THE WHOLE RUN, 16 UNITS

Sixteen lectures, 6h 07m, and for the only time in the playlist sixteen lectures against sixteen sheet rows — no lecture without a row, no row without a lecture. Units 01 to 07 are one table read seven ways; 08 to 10 change what a match MEANS; 11 to 16 drop to a single string and grow a carried state instead.

UNIT 01

THE LCS TABLE

▶ 47:094 DRILLS1 PROBLEM
UNIT 02

WALK IT BACKWARDS

▶ 16:553 DRILLS1 PROBLEM
UNIT 03

SUBSTRING, NOT SUBSEQUENCE

▶ 14:013 DRILLS1 PROBLEM
UNIT 04

PALINDROME BY REVERSAL

▶ 9:383 DRILLS1 PROBLEM
UNIT 05

INSERT TO MIRROR

▶ 12:003 DRILLS1 PROBLEM
UNIT 06

TWO OPERATIONS, ONE TABLE

▶ 7:303 DRILLS1 PROBLEM
UNIT 07

SHORTEST SUPERSEQUENCE

▶ 26:443 DRILLS1 PROBLEM
UNIT 08

COUNT THE CARVINGS

▶ 40:154 DRILLS1 PROBLEM
UNIT 09

EDIT DISTANCE

▶ 37:394 DRILLS1 PROBLEM
UNIT 10

WILDCARDS

▶ 43:524 DRILLS1 PROBLEM
UNIT 11

ONE PASS, NO TABLE

▶ 9:113 DRILLS1 PROBLEM
UNIT 12

THE HOLDING FLAG

▶ 35:343 DRILLS1 PROBLEM
UNIT 13

AT MOST TWO

▶ 31:503 DRILLS1 PROBLEM
UNIT 14

AT MOST K

▶ 12:243 DRILLS1 PROBLEM
UNIT 15

COOLDOWN

▶ 15:213 DRILLS1 PROBLEM
UNIT 16

A FEE PER TRADE

▶ 7:203 DRILLS1 PROBLEM
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
08 / INDEX PRESS I FROM ANYWHERE

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

DP on Strings · 10
DP on Stocks · 06
SOLVED HAS A JUDGE LINK
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
09 / INTRO UNIT 01 · THE LCS TABLE

UNIT 01 — THE LCS TABLE

Two indices, one per string — the table every string row here reuses

THE QUESTION THIS LECTURE ANSWERS

WHAT IS THE LONGEST SEQUENCE OF CHARACTERS THESE TWO STRINGS SHARE, IN ORDER?

subsequenceLCSempty prefix1-indexed shift
WHAT TO WATCH FOR
  • 01A LENGTH-n STRING HAS 2ⁿ SUBSEQUENCES — WHICH IS WHY BRUTE FORCE DIES
  • 02A MATCH IS FREE TO TAKE: BANK ONE AND STEP DIAGONALLY
  • 03A MISMATCH TRIES BOTH DROPS AND KEEPS THE BETTER
  • 04THE TABLE SHIFTS TO 1-BASED SO ROW 0 IS THE EMPTY PREFIX
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
10 / VIDEO UNIT 01 · THE LCS TABLE

DP 25 · Longest Common Subsequence

STRIVER A2Z
Subsequences counted · match and mismatch branches · the 1-indexed shift
RUNTIME 47:09
AFTER THIS → 4 DRILLS · PROBLEM #01
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
11 / DRILL UNIT 01 · THE LCS TABLE · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The lecture opens by counting subsequences of a length-n string. How many are there?

Each character is independently in or out, so 2ⁿ — the same pick / not-pick that deck II ran on numbers, now on characters. It is also why brute force is hopeless and why the table has to exist.

DRILL 02 · RECALL

Characters at i and j MATCH. What does the transition do?

A matching pair can always be taken — no better answer ever skips it — so you bank the 1 and shrink both strings. That certainty is what makes this an O(n·m) table rather than a search.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
12 / DRILL UNIT 01 · THE LCS TABLE · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Characters DON'T match. What happens?

max(f(i−1, j), f(i, j−1)). You cannot know which character to discard, so you try both and keep whichever leads further. Two branches per cell, exactly as in decks I and II.

DRILL 02 · RECALL

The tabulated version shifts to 1-based indexing. Why is that worth the confusion?

The recurrence reads i−1 and j−1, which at index 0 would be −1. Shifting by one turns that into row 0 meaning 'empty string', which is genuinely 0 — so the base case IS the extra row, and no guard is needed anywhere.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
13 / MECHANISM UNIT 01 · LCS · CODE MIRRORED

TWO STRINGS, TWO INDICES

abcde against ace. Row and column 0 are the EMPTY prefix, which is why the table is one larger than the strings and why i-1 never needs a guard. Characters match → bank one and step diagonally; they do not → drop one from each side and keep the better. Watch which cells each answer reads.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
14 / PROBLEM #01 · LCS · HARD

Longest common subsequence

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

Two strings and the words “longest common”. One index per string, and the answer is a length rather than a string — which is what makes it a table and not a search.

INTUITION

Compare the last characters. If they match, that pair can always be taken — no answer is made worse by banking it — so add one and shrink both strings. If they do not, you cannot know which to discard, so try both and keep the better. The table is one larger than the strings so that row 0 means 'the empty prefix', which is genuinely 0 and removes every bounds check.

STEPS
  1. State: f(i, j) = LCS of a's first i characters and b's first j.
  2. Match: 1 + f(i−1, j−1). The pair is free to take.
  3. Mismatch: max(f(i−1, j), f(i, j−1)). Try dropping either.
  4. Base: row and column 0 are 0 — nothing in common with nothing.
  5. Keep two rows rather than the whole table.
BRUTEO(2ⁿ · m)
OPTIMALO(n·m)
↕ SCROLL
int lcs(string& a, string& b) {
    int n = a.size(), m = b.size();
    vector<int> prev(m + 1, 0), cur(m + 1, 0);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (a[i-1] == b[j-1]) cur[j] = 1 + prev[j-1];   // bank the match
            else                  cur[j] = max(prev[j], cur[j-1]);
        }
        prev = cur;
    }
    return prev[m];
}
TIMEO(n·m)one cell per pair of prefixes
SPACEO(m)two rows, rolled
TRAP

Indexing the strings with i and j rather than i−1 and j−1 after the 1-based shift. The table is 1-indexed and the strings are not, and mixing them reads the wrong characters — producing a smaller answer on most inputs and the right one on a few.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
15 / INTRO UNIT 02 · WALK IT BACKWARDS

UNIT 02 — WALK IT BACKWARDS

Reading a string back out of a table that only stored numbers

THE QUESTION THIS LECTURE ANSWERS

THE TABLE GIVES THE LENGTH. HOW DO YOU RECOVER THE ACTUAL SUBSEQUENCE?

reconstructionbackward walkretracing the fill
WHAT TO WATCH FOR
  • 01THE ANSWER IS ALREADY IN THE TABLE — STORING STRINGS IN CELLS IS WASTE
  • 02ON A MATCH: RECORD IT AND STEP DIAGONALLY
  • 03ON A MISMATCH: FOLLOW THE LARGER NEIGHBOUR — RETRACE WHAT THE FILL CHOSE
  • 04YOU WALK BACKWARDS, SO REVERSE THE STRING AT THE END
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
16 / VIDEO UNIT 02 · WALK IT BACKWARDS

DP 26 · Print Longest Common Subsequence

STRIVER A2Z
Walking the finished table backwards · which neighbour to follow · reversing at the end
RUNTIME 16:55
AFTER THIS → 3 DRILLS · PROBLEM #02
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
17 / DRILL UNIT 02 · WALK IT BACKWARDS · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

To recover the actual subsequence rather than its length, what do you do?

The table already contains the answer — you just have to read it. Storing strings in cells costs O(n·m·length) memory for information the numbers already imply. Reconstruction by walking back is the general technique, not an LCS trick.

DRILL 02 · RECALL

During the backward walk you are at (i, j) and the characters DON'T match. Where do you go?

You retrace the choice the fill made, and the fill took the max — so follow the larger of up and left. Following the smaller walks a path that was never optimal and prints a shorter string with total confidence.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
18 / DRILL UNIT 02 · WALK IT BACKWARDS · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Characters match during the walk. What do you do?

A match was banked by the fill, so it belongs in the answer and both strings shrink. Because you are walking backwards the characters come out reversed — remember to flip the string at the end, which is the one step everyone forgets.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
19 / PROBLEM #02 · LCS · HARD

Print Longest Common Subsequence | (DP - 26)

HARD lcs ▶ SOLVE ON GEEKSFORGEEKSThe GfG problem asks for every LCS in lexicographic order; the lecture reconstructs one by walking the table backwards. Do the walk first — it is the transferable technique — then extend it to all of them.
SIGNAL — WHAT GIVES IT AWAY

“Print” or “return the subsequence” rather than its length. The table already holds the answer; the work is reading it back out.

INTUITION

Start at the bottom-right and retrace the decisions the fill made. On a match, that character was banked — record it and step diagonally. On a mismatch, the fill took the larger neighbour, so follow the larger. Because you walk backwards, the characters come out reversed.

STEPS
  1. Fill the ordinary LCS table — the full table, not two rolled rows.
  2. Start at (n, m).
  3. Match: append the character and move diagonally.
  4. Mismatch: move toward the LARGER of up and left.
  5. Stop at row or column 0, then reverse the string you built.
BRUTEO(2ⁿ · m)
OPTIMALO(n·m)
↕ SCROLL
string printLCS(string& a, string& b) {
    int n = a.size(), m = b.size();
    vector<vector<int>> dp(n+1, vector<int>(m+1, 0));   // full table needed
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            dp[i][j] = (a[i-1] == b[j-1]) ? 1 + dp[i-1][j-1]
                                          : max(dp[i-1][j], dp[i][j-1]);
    string out;
    int i = n, j = m;
    while (i > 0 && j > 0) {
        if (a[i-1] == b[j-1]) { out += a[i-1]; i--; j--; }   // on the diagonal
        else if (dp[i-1][j] > dp[i][j-1]) i--;               // follow the LARGER
        else j--;
    }
    reverse(out.begin(), out.end());     // walked backwards, so flip it
    return out;
}
TIMEO(n·m)fill plus a walk of length ≤ n+m
SPACEO(n·m)the whole table is needed for the walk
TRAP

Space-optimising the fill to two rows and then trying to walk back. The walk needs every cell, so this is the one problem in the deck where the O(m) optimisation is not available — a real trade, not an oversight.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
20 / INTRO UNIT 03 · SUBSTRING, NOT SUBSEQUENCE

UNIT 03 — SUBSTRING, NOT SUBSEQUENCE

One cell of difference, and a different place to read the answer

THE QUESTION THIS LECTURE ANSWERS

SAME TWO STRINGS, BUT THE COMMON PART MUST BE CONSECUTIVE. WHAT CHANGES?

substringrunanswer location
WHAT TO WATCH FOR
  • 01SUBSTRING = CONSECUTIVE, SUBSEQUENCE = NOT NECESSARILY. HE STRESSES IT
  • 02A MISMATCH SETS THE CELL TO 0 — IT INHERITS NOTHING
  • 03“YOU DON'T WANT ANY INTERRUPTION” — THAT IS THE WHOLE ARGUMENT
  • 04THE ANSWER IS THE LARGEST CELL ANYWHERE, NOT THE CORNER
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
21 / VIDEO UNIT 03 · SUBSTRING, NOT SUBSEQUENCE

DP 27 · Longest Common Substring

STRIVER A2Z
Substring vs subsequence · why a mismatch resets to 0 · the answer is the largest cell
RUNTIME 14:01
AFTER THIS → 3 DRILLS · PROBLEM #03
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
22 / DRILL UNIT 03 · SUBSTRING, NOT SUBSEQUENCE · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The lecture stresses the difference between the two words. What is it?

Consecutiveness is the whole delta, and it is what forbids the max-of-neighbours branch: the moment characters disagree, any run in progress is broken and the count must restart at zero rather than inheriting.

DRILL 02 · RECALL

Characters DON'T match. What goes in the cell?

'You are not dependent on the previous guys, because you don't want any interruption.' Inheriting the neighbour's value is exactly the LCS behaviour, and it is what would let a broken run continue. This one cell is the entire difference between the two problems.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
23 / DRILL UNIT 03 · SUBSTRING, NOT SUBSEQUENCE · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Where does the answer live at the end?

Each cell is the length of a run ENDING exactly there, so the best run may end anywhere. Reading the corner gives you the run that happens to end at both string ends — usually 0. Same shape as deck I's variable-ending-point problems.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
24 / MECHANISM UNIT 03 · SUBSTRING · CODE MIRRORED

ONE CELL APART FROM LCS

abcde against abfce, but now the run must be consecutive. Identical table, identical matching branch, and on a mismatch the cell becomes 0 instead of inheriting a neighbour. The answer is no longer the corner, either: it is the largest cell anywhere.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
25 / PROBLEM #03 · LCS · HARD

Longest Common Substring

HARD lcs ▶ SOLVE ON GEEKSFORGEEKS
SIGNAL — WHAT GIVES IT AWAY

The word substring rather than subsequence, or the word “consecutive”. Everything else is identical to #01.

INTUITION

A run of matching characters cannot survive an interruption, so the moment two characters disagree the cell drops to 0 rather than inheriting a neighbour. Each cell then means 'the longest run ENDING exactly here' — and because a run may end anywhere, the answer is the largest cell in the table rather than the corner.

STEPS
  1. State: f(i, j) = length of the common run ending at a[i−1] and b[j−1].
  2. Match: 1 + f(i−1, j−1), exactly as in LCS.
  3. Mismatch: 0. Inherit nothing.
  4. Track the running maximum as you fill.
  5. Return that maximum, not the last cell.
BRUTEO(n·m·min(n,m))
OPTIMALO(n·m)
↕ SCROLL
int longestCommonSubstring(string& a, string& b) {
    int n = a.size(), m = b.size(), best = 0;
    vector<int> prev(m + 1, 0), cur(m + 1, 0);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (a[i-1] == b[j-1]) {
                cur[j] = 1 + prev[j-1];
                best = max(best, cur[j]);   // answer is the LARGEST cell
            } else {
                cur[j] = 0;                 // the run BREAKS - inherit nothing
            }
        }
        prev = cur;
    }
    return best;
}
TIMEO(n·m)one cell per pair of positions
SPACEO(m)two rows, rolled
TRAP

Reading the bottom-right cell. It is the run that ends at BOTH string ends, which is usually 0 — so the function returns 0 for inputs with an obvious common run, and occasionally returns the right answer by coincidence.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
26 / INTRO UNIT 04 · PALINDROME BY REVERSAL

UNIT 04 — PALINDROME BY REVERSAL

Reversing a string to reuse a solved problem

THE QUESTION THIS LECTURE ANSWERS

WHAT IS THE LONGEST PALINDROME HIDING INSIDE THIS STRING AS A SUBSEQUENCE?

palindromereversalreduction
WHAT TO WATCH FOR
  • 01A PALINDROME READS THE SAME BOTH WAYS, SO IT LIVES IN s AND reverse(s)
  • 02NINE MINUTES, BECAUSE THERE IS NO NEW RECURRENCE — JUST A REVERSED ARGUMENT
  • 03IT MUST BE LCS, NOT SUBSTRING: A PALINDROMIC SUBSEQUENCE NEED NOT BE CONTIGUOUS
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
27 / VIDEO UNIT 04 · PALINDROME BY REVERSAL

DP 28 · Longest Palindromic Subsequence

STRIVER A2Z
Palindrome as a common subsequence with the reverse · why it must be LCS not substring
RUNTIME 9:38
AFTER THIS → 3 DRILLS · PROBLEM #04
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
28 / DRILL UNIT 04 · PALINDROME BY REVERSAL · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The longest palindromic subsequence of s equals what?

A palindrome reads the same forwards and backwards, so it appears in both s and reverse(s) — and any subsequence common to both is a palindrome. Nine minutes of lecture because there is no new recurrence, just a reversed string handed to a solved function.

DRILL 02 · RECALL

Why must the reduction use LCS rather than longest common SUBSTRING?

'bbbab' has palindromic subsequence 'bbb', which is not contiguous. Using substring would return only the longest contiguous palindrome — a real but different problem. The previous unit's distinction, cashed in immediately.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
29 / DRILL UNIT 04 · PALINDROME BY REVERSAL · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · TRANSFER

s = "bbbab". What is the length of its longest palindromic subsequence?

"bbbb" — take the three b's plus the trailing b, skipping the a. Length 4. The greedy read of 'bbb' at the front gives 3 and misses that the last b joins them; the table does not miss it.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
30 / PROBLEM #04 · LCS · HARD

Longest Palindromic Subsequence

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

One string, and “longest palindromic subsequence”. A single-string problem that becomes a two-string problem the moment you write the string twice.

INTUITION

A palindrome reads identically forwards and backwards, so it appears in s AND in reverse(s) — and conversely, anything common to both reads the same either way. So the answer is LCS(s, reverse(s)) and there is no new recurrence to write.

STEPS
  1. Reverse s into t.
  2. Return LCS(s, t) using problem #01 unchanged.
  3. Note it must be LCS, not longest common SUBSTRING — a palindromic subsequence need not be contiguous.
BRUTEO(2ⁿ)
OPTIMALO(n²)
↕ SCROLL
int longestPalindromeSubseq(string s) {
    string t = s;
    reverse(t.begin(), t.end());   // a palindrome lives in s AND reverse(s)
    return lcs(s, t);              // no new recurrence at all
}
TIMEO(n²)the LCS table over s and its reverse
SPACEO(n)two rows, rolled
TRAP

Reaching for longest common substring instead. On 'bbbab' that returns 3 rather than 4, because the answer 'bbbb' is not contiguous — a smaller, plausible number from the wrong one of two nearly identical tables.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
31 / INTRO UNIT 05 · INSERT TO MIRROR

UNIT 05 — INSERT TO MIRROR

Two reductions stacked — insertions counted without ever placing one

THE QUESTION THIS LECTURE ANSWERS

HOW FEW CHARACTERS CAN YOU INSERT TO TURN THIS STRING INTO A PALINDROME?

insertionLPSstacked reduction
WHAT TO WATCH FOR
  • 01THE ANSWER IS n MINUS THE LONGEST PALINDROMIC SUBSEQUENCE
  • 02“YOU CAN INSERT ANY CHARACTER ANYWHERE” — HE STOPS ON THIS
  • 03WHAT ALREADY FORMS A PALINDROME STAYS; EVERYTHING ELSE NEEDS A MIRROR
  • 04YOU NEVER WORK OUT WHERE THEY GO — THE COUNT IS THE ANSWER
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
32 / VIDEO UNIT 05 · INSERT TO MIRROR

DP 29 · Minimum Insertions to Make String Palindrome

STRIVER A2Z
n − LPS · why insertions may go anywhere · counting without simulating
RUNTIME 12:00
AFTER THIS → 3 DRILLS · PROBLEM #05
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
33 / DRILL UNIT 05 · INSERT TO MIRROR · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Minimum insertions to make s a palindrome equals what?

Whatever already forms a palindrome can be kept; every other character needs a partner inserted. So the cost is n − LPS, and LPS is the previous unit. Two reductions stacked — this is LCS underneath, twice removed.

DRILL 02 · RECALL

The lecture stresses one freedom in the problem statement. Which?

'You can insert any character anywhere — that's the point.' If insertions were end-only the answer would be different and larger. The freedom is what lets every unmatched character be paired independently, which is what makes n − LPS exact.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
34 / DRILL UNIT 05 · INSERT TO MIRROR · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · TRANSFER

s = "abcaa", whose longest palindromic subsequence is "aca" (length 3). Minimum insertions?

5 − 3 = 2. The three characters of "aca" stay put and the other two each need a mirror inserted. Note you never have to work out WHERE they go — the count alone answers the question.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
35 / PROBLEM #05 · LCS · HARD

Minimum insertions to make string palindrome | DP-29

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

“Minimum insertions to make it a palindrome”, with insertions allowed anywhere. Two reductions deep: this is LPS, which is LCS.

INTUITION

Whatever already forms a palindrome can be left alone; every other character needs a mirror inserted opposite it. So the cost is n minus the longest palindromic subsequence. Because insertions may go anywhere, each unmatched character can be paired independently — which is what makes the count exact.

STEPS
  1. Compute the longest palindromic subsequence of s (problem #04).
  2. Return n − that.
  3. Note you never have to decide WHERE the insertions go — the count is the answer.
BRUTEO(2ⁿ)
OPTIMALO(n²)
↕ SCROLL
int minInsertions(string s) {
    // whatever already forms a palindrome stays; everything else needs
    // a mirror inserted somewhere - and insertions may go ANYWHERE.
    return (int)s.size() - longestPalindromeSubseq(s);
}
TIMEO(n²)one LCS table over s and its reverse
SPACEO(n)two rows, rolled
TRAP

Assuming insertions must go at the ends. They may go anywhere, and restricting them gives a larger answer that is correct for a different problem. Reading that one clause of the statement is the whole difficulty.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
36 / INTRO UNIT 06 · TWO OPERATIONS, ONE TABLE

UNIT 06 — TWO OPERATIONS, ONE TABLE

Two operations, both priced off the same table

THE QUESTION THIS LECTURE ANSWERS

HOW FEW INSERTIONS AND DELETIONS TURN STRING A INTO STRING B?

insertdeleteleftoversorder preservation
WHAT TO WATCH FOR
  • 01THE LCS SURVIVES UNTOUCHED — EVERYTHING ELSE IS DELETED OR INSERTED
  • 02COST IS (len A − LCS) + (len B − LCS), THE TWO LEFTOVERS ADDED
  • 03IT MUST BE A SUBSEQUENCE, NOT A SET: INSERT AND DELETE CANNOT REORDER
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
37 / VIDEO UNIT 06 · TWO OPERATIONS, ONE TABLE

DP 30 · Minimum Insertions/Deletions to Convert A to B

STRIVER A2Z
The LCS survives · deletions from A, insertions into B · why order matters
RUNTIME 7:30
AFTER THIS → 3 DRILLS · PROBLEM #06
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
38 / DRILL UNIT 06 · TWO OPERATIONS, ONE TABLE · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Converting A to B with insertions and deletions only. What is the total cost?

The LCS survives untouched. Everything else in A is deleted and everything else in B is inserted, so the cost is the two leftovers added. Third reduction to the same table in four units — which is the point the deck keeps making.

DRILL 02 · RECALL

Why is the LCS specifically the right thing to keep?

Order matters because insertions and deletions cannot reorder anything. A common SET of characters would be useless — they must appear in the same relative order in both, which is precisely the definition of a common subsequence.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
39 / DRILL UNIT 06 · TWO OPERATIONS, ONE TABLE · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · TRANSFER

A = "abcd" (4), B = "anc" (3), LCS = "ac" (2). Total operations?

(4 − 2) deletions + (3 − 2) insertions = 2 + 1 = 3. Delete b and d, insert n. Counting them separately and adding is the whole method — there is nothing to simulate.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
40 / PROBLEM #06 · LCS · HARD

Minimum insertions or deletions to convert string A to B

HARD lcs ▶ SOLVE ON GEEKSFORGEEKSLeetCode 583, Delete Operation for Two Strings, is the same problem counting only deletions from both sides. Either judge exercises the identical LCS reduction.
SIGNAL — WHAT GIVES IT AWAY

“Convert A to B” with insertions and deletions but no replacement. The absence of replace is what keeps this at LCS rather than at edit distance.

INTUITION

The longest common subsequence survives both operations untouched — it is already in the right order in both strings. Everything A has beyond it must be deleted, and everything B has beyond it must be inserted. So the cost is the two leftovers added, and no simulation is needed.

STEPS
  1. Compute LCS(A, B).
  2. Deletions = len(A) − LCS.
  3. Insertions = len(B) − LCS.
  4. Return their sum: len(A) + len(B) − 2·LCS.
BRUTEO(2ⁿ · m)
OPTIMALO(n·m)
↕ SCROLL
int minOperations(string& a, string& b) {
    int k = lcs(a, b);             // the common part survives untouched
    return (a.size() - k)          // delete what A has beyond it
         + (b.size() - k);         // insert what B has beyond it
}
TIMEO(n·m)one LCS table
SPACEO(m)two rows, rolled
TRAP

Subtracting the LCS once instead of twice. That gives the length of the shortest common SUPERSEQUENCE — a real quantity, for the next problem. The same three numbers answer two different questions, and confusing them never crashes.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
41 / INTRO UNIT 07 · SHORTEST SUPERSEQUENCE

UNIT 07 — SHORTEST SUPERSEQUENCE

Building a string by merging two, sharing what they have in common

THE QUESTION THIS LECTURE ANSWERS

WHAT IS THE SHORTEST STRING THAT CONTAINS BOTH OF THESE AS SUBSEQUENCES?

supersequencemergereconstruction
WHAT TO WATCH FOR
  • 01LENGTH IS n + m − LCS: SHARED CHARACTERS ARE WRITTEN ONCE, NOT TWICE
  • 02HE NAMES TWO PREREQUISITES: LCS AND PRINTING IT. BOTH ARE NEEDED HERE
  • 03THIS IS WHERE UNIT 02'S BACKWARD WALK STOPS BEING OPTIONAL
  • 04ON A MISMATCH YOU WRITE THE CHARACTER YOU STEP AWAY FROM
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
42 / VIDEO UNIT 07 · SHORTEST SUPERSEQUENCE

DP 31 · Shortest Common Supersequence

STRIVER A2Z
Length n + m − LCS · the backward walk that emits characters
RUNTIME 26:44
AFTER THIS → 3 DRILLS · PROBLEM #07
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
43 / DRILL UNIT 07 · SHORTEST SUPERSEQUENCE · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The shortest string containing both A and B as subsequences has what length?

Write both out and merge them; every character of the LCS is shared and so written once rather than twice. Subtracting twice would delete the shared characters entirely rather than de-duplicating them.

DRILL 02 · RECALL

The lecture names two prerequisites in its first minute. Which pair?

You need the table AND the backward walk, because the answer is a STRING and building it means retracing the fill. This is where unit 02's technique stops being optional and becomes the only way through.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
44 / DRILL UNIT 07 · SHORTEST SUPERSEQUENCE · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Walking the table backwards to BUILD the supersequence, what happens when characters don't match?

A non-matching character belongs to exactly one string and still has to appear, so it is written as you step past it. Matching characters are written once on the diagonal. Same walk as unit 02, but emitting more.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
45 / PROBLEM #07 · LCS · HARD

Shortest common supersequence

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

“Shortest string containing both as subsequences.” A construction problem: the answer is a string, so the table alone is not enough.

INTUITION

Write both strings out and merge them, sharing every character of the LCS rather than writing it twice — so the length is n + m − LCS. Building the actual string means walking the table backwards, emitting the shared characters once on the diagonal and the unshared ones as you step past them.

STEPS
  1. Fill the full LCS table.
  2. Walk back from (n, m).
  3. Match: emit the character once, step diagonally.
  4. Mismatch: emit the character from the side you step away from.
  5. Drain whatever remains of either string, then reverse the result.
BRUTEO(2^(n+m))
OPTIMALO(n·m)
↕ SCROLL
string shortestCommonSupersequence(string a, string b) {
    int n = a.size(), m = b.size();
    vector<vector<int>> dp(n+1, vector<int>(m+1, 0));
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            dp[i][j] = (a[i-1] == b[j-1]) ? 1 + dp[i-1][j-1]
                                          : max(dp[i-1][j], dp[i][j-1]);
    // length is n + m - lcs; build it by walking the table backwards
    string out;
    int i = n, j = m;
    while (i > 0 && j > 0) {
        if (a[i-1] == b[j-1]) { out += a[i-1]; i--; j--; }   // written ONCE
        else if (dp[i-1][j] > dp[i][j-1]) { out += a[i-1]; i--; }
        else                              { out += b[j-1]; j--; }
    }
    while (i > 0) { out += a[i-1]; i--; }     // whatever is left over
    while (j > 0) { out += b[j-1]; j--; }
    reverse(out.begin(), out.end());
    return out;
}
TIMEO(n·m)fill plus a walk of length ≤ n+m
SPACEO(n·m)the whole table is needed for the walk
TRAP

Emitting the matched character twice — once for each string. The result still contains both as subsequences, so it passes casual inspection, and it is simply not the shortest. Sharing the LCS is the entire point of the problem.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
46 / INTRO UNIT 08 · COUNT THE CARVINGS

UNIT 08 — COUNT THE CARVINGS

The one string table where a match is not forced

THE QUESTION THIS LECTURE ANSWERS

HOW MANY DISTINCT WAYS CAN THE SECOND STRING BE CARVED OUT OF THE FIRST?

countingcarvingasymmetric strings
WHAT TO WATCH FOR
  • 01“WHENEVER THE PROBLEM IS COUNT WAYS” — BASE RETURNS 1 OR 0, BRANCHES ADD
  • 02ON A MATCH YOU MAY USE IT OR SAVE IT — BOTH COUNT, SO THEY ADD
  • 03ONLY s IS FREE TO SKIP; t MUST BE MATCHED IN ORDER
  • 04EMPTY t IS ONE WAY; EMPTY s WITH t LEFT IS ZERO
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
47 / VIDEO UNIT 08 · COUNT THE CARVINGS

DP 32 · Distinct Subsequences

STRIVER A2Z
Count-ways base cases · why a match ADDS two branches · the asymmetry of s and t
RUNTIME 40:15
AFTER THIS → 4 DRILLS · PROBLEM #08
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
48 / DRILL UNIT 08 · COUNT THE CARVINGS · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The lecture names the giveaway that this is a counting problem. What is it?

'Whenever the problem is count ways, the base case has to return one or has to return zero, and then you add up the branches.' Same rule deck I used on climbing stairs — the pattern is stated as a general recipe rather than as a fact about this problem.

DRILL 02 · RECALL

Characters at i and j match. What does the count do?

Unlike LCS, a match here is not forced — that s-character could be used for this t-character or saved for a later one, and both give valid distinct subsequences. So both branches count and they add. This is the one place matching does NOT mean 'take it'.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
49 / DRILL UNIT 08 · COUNT THE CARVINGS · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Characters DON'T match. What happens?

You are carving t out of s, so s may be skipped freely but t must be matched in order. An unmatched s character is simply discarded. The asymmetry — one string free, one string fixed — is what distinguishes this from every other table in the deck.

DRILL 02 · RECALL

Base cases: what is the count when t is exhausted, and when s is exhausted but t is not?

An empty t has been fully matched — that is one complete way. A non-empty t with no s left can never be completed — zero ways. Getting these backwards inverts the entire answer, and they are the reason the counting rule above is stated the way it is.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
50 / MECHANISM UNIT 08 · DISTINCT · CODE MIRRORED

A MATCH YOU DO NOT HAVE TO TAKE

How many ways can rabbit be carved out of rabbbit? Three, and the reason is the matching branch: that b could be used here or saved for later, so both branches count and they ADD. Every other string table in this deck treats a match as forced; this one does not.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
51 / PROBLEM #08 · MATCH · HARD

Distinct subsequences

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

“How many distinct subsequences of s equal t.” Counting rather than measuring, over two strings — and note the asymmetry: t must be matched in order, s may be skipped freely.

INTUITION

This is the one string table where a match is NOT forced. That s-character can serve this t-character, or be saved for a later one, and both give valid distinct subsequences — so the branches add. On a mismatch only the skip-s branch survives, because t may never be skipped.

STEPS
  1. State: f(i, j) = ways to form t's first j characters from s's first i.
  2. Match: f(i−1, j−1) + f(i−1, j). Use it, or save it.
  3. Mismatch: f(i−1, j). Discard the s character.
  4. Base: empty t is 1 way; empty s with t remaining is 0 ways.
  5. Counts overflow int — use a 64-bit accumulator or the judge's modulus.
BRUTEO(2ⁿ)
OPTIMALO(n·m)
↕ SCROLL
int numDistinct(string s, string t) {
    int n = s.size(), m = t.size();
    vector<double> prev(m + 1, 0), cur(m + 1, 0);
    prev[0] = cur[0] = 1;                  // empty target: exactly one way
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (s[i-1] == t[j-1])
                cur[j] = prev[j-1] + prev[j];   // USE it, or SAVE it - ADD
            else
                cur[j] = prev[j];               // skip s; t cannot move
        }
        prev = cur;
    }
    return (int)prev[m];
}
TIMEO(n·m)one cell per pair of prefixes
SPACEO(m)two rows, rolled
TRAP

Treating a match as forced, out of habit from LCS. Taking only the diagonal undercounts every case where a character could have been used later — the answer comes out smaller and completely believable.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
52 / INTRO UNIT 09 · EDIT DISTANCE

UNIT 09 — EDIT DISTANCE

Three branches per cell — the first table in the step that needs them

THE QUESTION THIS LECTURE ANSWERS

HOW FEW EDITS TURN ONE STRING INTO ANOTHER, WITH INSERT, DELETE AND REPLACE?

insertdeletereplaceLevenshtein
WHAT TO WATCH FOR
  • 01THREE OPTIONS: INSERT, DELETE, REPLACE, EACH COSTING ONE — TAKE THE MIN
  • 02A MATCH IS FREE. CHARGING 1 INFLATES EVERY ANSWER BY THE LCS LENGTH
  • 03THE BASE ROW IS 0, 1, 2, 3… — A RAMP, NOT ZEROS
  • 04HIS EXAMPLE IS exection → execution, WHICH IS ONE INSERTION
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
53 / VIDEO UNIT 09 · EDIT DISTANCE

DP 33 · Edit Distance

STRIVER A2Z
The three operations · a match costs nothing · the base cases are a ramp
RUNTIME 37:39
AFTER THIS → 4 DRILLS · PROBLEM #09
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
54 / DRILL UNIT 09 · EDIT DISTANCE · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Characters don't match. How many options does the recurrence try?

Insert (j−1), delete (i−1) and replace (both back), each costing 1, and you take the min of the three. Deck I and II had two branches per cell; this is the first table in the whole step with three.

DRILL 02 · RECALL

Characters DO match. What is the cost?

Nothing needs doing, so no cost is added and both indices advance. Charging 1 here is the classic slip and it inflates the answer by exactly the length of the LCS — a wrong number that scales plausibly with the input.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
55 / DRILL UNIT 09 · EDIT DISTANCE · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

One string is empty. What is the edit distance?

Every remaining character has to be inserted or deleted, one operation each. This is why the tabulated version fills row 0 with 0..m and column 0 with 0..n rather than with zeros — the base cases are a ramp, not a flat edge.

DRILL 02 · TRANSFER

The lecture's own example: "exection" to "execution". What is the distance?

One insertion — 'u' after 'exec'. The strings differ in length by exactly one and share everything else in order, so a single operation suffices. Worth doing by eye before trusting a table: a sanity check you can run in an interview.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
56 / MECHANISM UNIT 09 · EDIT · CODE MIRRORED

THREE BRANCHES, NOT TWO

horse to ros. The first table in this whole step that reads three cells: insert from the left, delete from above, replace from the diagonal, each costing one. A match costs nothing and slides across the diagonal, and the base row is a ramp, not a row of zeros.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
57 / PROBLEM #09 · MATCH · HARD

Edit distance

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

“Minimum operations to convert” with insert, delete AND replace. The third operation is what makes this three branches rather than two.

INTUITION

At each pair of positions: if the characters match, nothing needs doing and you slide diagonally at no cost. If they do not, you may insert (advance the target), delete (advance the source) or replace (advance both), each costing one — take the cheapest. The base cases are ramps, because converting to or from an empty string costs one operation per remaining character.

STEPS
  1. State: f(i, j) = edits converting a's first i characters into b's first j.
  2. Match: f(i−1, j−1), cost 0.
  3. Mismatch: 1 + min(f(i, j−1) insert, f(i−1, j) delete, f(i−1, j−1) replace).
  4. Base: f(0, j) = j and f(i, 0) = i — a ramp, not zeros.
  5. Keep two rows.
BRUTEO(3^(n+m))
OPTIMALO(n·m)
↕ SCROLL
int minDistance(string a, string b) {
    int n = a.size(), m = b.size();
    vector<int> prev(m + 1), cur(m + 1);
    for (int j = 0; j <= m; j++) prev[j] = j;      // base row is a RAMP
    for (int i = 1; i <= n; i++) {
        cur[0] = i;                                // base column too
        for (int j = 1; j <= m; j++) {
            if (a[i-1] == b[j-1]) cur[j] = prev[j-1];   // a match is FREE
            else cur[j] = 1 + min({cur[j-1],       // insert
                                   prev[j],        // delete
                                   prev[j-1]});    // replace
        }
        prev = cur;
    }
    return prev[m];
}
TIMEO(n·m)three branches per cell, all O(1)
SPACEO(m)two rows, rolled
TRAP

Charging 1 for a matching pair. It inflates the answer by exactly the length of the common subsequence — a number that grows sensibly with the input, never crashes, and is wrong on every input with any characters in common.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
58 / INTRO UNIT 10 · WILDCARDS

UNIT 10 — WILDCARDS

A pattern with power on one side, literal text on the other

THE QUESTION THIS LECTURE ANSWERS

DOES THIS PATTERN, WITH ? AND *, MATCH THIS STRING?

wildcardpattern matchingstar branches
WHAT TO WATCH FOR
  • 01? IS EXACTLY ONE CHARACTER; * IS ANY RUN, INCLUDING EMPTY
  • 02WILDCARDS LIVE ONLY IN THE PATTERN — HE STATES THIS EXPLICITLY
  • 03A STAR HAS TWO BRANCHES: SKIP IT, OR SWALLOW ONE MORE AND STAY
  • 04STRING EXHAUSTED, PATTERN LEFT: A MATCH ONLY IF ALL THAT REMAINS IS STARS
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
59 / VIDEO UNIT 10 · WILDCARDS

DP 34 · Wildcard Matching

STRIVER A2Z
What ? and * mean · the two branches of a star · the trailing-star base case
RUNTIME 43:52
AFTER THIS → 4 DRILLS · PROBLEM #10
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
60 / DRILL UNIT 10 · WILDCARDS · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

What does '?' match, and what does '*' match?

'?' is a single-character slot; '*' can absorb nothing at all or the entire rest of the string. That 'including empty' is what makes '*' two branches rather than one, and forgetting it fails on the shortest inputs.

DRILL 02 · RECALL

The pattern is p and the string is s. Where can the wildcards appear?

'This question mark or the star will only be in string s1, it will not be in s2.' The asymmetry is what makes this a matching problem rather than a comparison — one side is a pattern with power, the other is literal text.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
61 / DRILL UNIT 10 · WILDCARDS · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The pattern character is '*'. What are the two branches?

OR the two: consume nothing and move past the '*', or let it swallow one more character of s and stay on the '*'. Repeated, that covers every possible length — and the 'stay on the star' branch is the same stay-put move unbounded knapsack used.

DRILL 02 · RECALL

The string is exhausted but pattern characters remain. When is it still a match?

'*' can match the empty sequence, so trailing stars are harmless; anything else demands a character that no longer exists. Returning false unconditionally here is the most common wildcard bug and it fails only on inputs ending in stars.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
62 / PROBLEM #10 · MATCH · HARD

Wildcard matching

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

A pattern containing ? and * against a literal string. The asymmetry is the tell: one side has power, the other is text.

INTUITION

? consumes exactly one character, so it behaves like a match. * is the interesting one: it may consume nothing at all, or swallow one more character and remain available — two branches, OR-ed. Repeated, that covers every possible length, and the 'stay put' branch is the same move unbounded knapsack used in deck II.

STEPS
  1. State: f(i, j) = does p's first j characters match s's first i?
  2. '*': f(i−1, j) OR f(i, j−1) — swallow one more, or move past the star.
  3. '?' or an equal character: f(i−1, j−1).
  4. Otherwise false.
  5. Base: empty pattern matches only an empty string; a pattern of only stars matches the empty string.
BRUTEO(2^(n+m))
OPTIMALO(n·m)
↕ SCROLL
bool isMatch(string s, string p) {
    int n = s.size(), m = p.size();
    vector<bool> prev(m + 1, false), cur(m + 1, false);
    prev[0] = true;                            // empty pattern, empty string
    for (int j = 1; j <= m; j++)               // leading stars match empty
        prev[j] = prev[j-1] && p[j-1] == '*';
    for (int i = 1; i <= n; i++) {
        cur[0] = false;                        // non-empty s, empty pattern
        for (int j = 1; j <= m; j++) {
            if (p[j-1] == '*')
                cur[j] = prev[j]               // swallow one more, stay on *
                      || cur[j-1];             // match nothing, move past *
            else if (p[j-1] == '?' || p[j-1] == s[i-1])
                cur[j] = prev[j-1];
            else
                cur[j] = false;
        }
        prev = cur;
    }
    return prev[m];
}
TIMEO(n·m)one cell per pair of prefixes
SPACEO(m)two rows, rolled
TRAP

Returning false whenever the string is exhausted and pattern remains. Trailing stars match the empty sequence, so this fails exactly on inputs ending in '*' — a narrow, easily-missed slice of the test cases.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
63 / INTRO UNIT 11 · ONE PASS, NO TABLE

UNIT 11 — ONE PASS, NO TABLE

A stock answer with no state at all — the baseline the rest add to

THE QUESTION THIS LECTURE ANSWERS

ONE BUY AND ONE SELL. WHAT IS THE MOST YOU CAN MAKE?

single passrunning minimumprofit floor
WHAT TO WATCH FOR
  • 01ONE PASS: TRACK THE MINIMUM PRICE SO FAR AND THE BEST PROFIT AGAINST IT
  • 02NO TABLE AND NO STATE — WHICH IS EXACTLY WHY IT OPENS THE SECTION
  • 03DOING NOTHING IS LEGAL, SO PROFIT IS FLOORED AT 0, NEVER NEGATIVE
  • 04HE WARNS AGAINST SKIPPING AHEAD — EACH ROW ADDS ONE THING TO THIS
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
64 / VIDEO UNIT 11 · ONE PASS, NO TABLE

DP 35 · Best Time to Buy and Sell Stock

STRIVER A2Z
The single pass · why profit is floored at zero · what a stateless solution looks like
RUNTIME 9:11
AFTER THIS → 3 DRILLS · PROBLEM #11
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
65 / DRILL UNIT 11 · ONE PASS, NO TABLE · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

One buy, one sell, sell must come after buy. What does the one-pass solution track?

At each day, the best sale today is today's price minus the cheapest day before it — so one variable for the running minimum and one for the best profit. No table, no state: this row is here to show what the LATER rows are adding state to.

DRILL 02 · RECALL

The lecture insists on watching this section in order. Why does it say that matters?

'In DP on stocks people tend to expect you to answer the space optimisation technique.' Each row adds exactly one thing to the state, so arriving at #14 cold means meeting three additions at once instead of one.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
66 / DRILL UNIT 11 · ONE PASS, NO TABLE · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

What is the answer when prices only ever fall?

Doing nothing is legal, so profit is floored at 0 and never negative. Every later row inherits this floor, which is why their 'not holding, no transactions used' state starts at 0 rather than at minus infinity.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
67 / PROBLEM #11 · STOCKS · MED

Best time to buy and sell stock

MED stocks ▶ SOLVE ON LEETCODEThis row needs no DP at all — one pass tracking the minimum price so far solves it. It opens the section because it establishes what the state would have to be, and every later row adds to that state rather than replacing it.
SIGNAL — WHAT GIVES IT AWAY

One buy, one sell, and the sell must come after the buy. No DP is needed — this row is here to establish the baseline the next five add to.

INTUITION

The best sale on day i is today's price minus the cheapest day before it. So sweep once carrying the running minimum and the best profit against it. Profit is floored at 0 because doing nothing is legal — a floor every later problem inherits.

STEPS
  1. Track the cheapest price seen so far, starting at prices[0].
  2. At each day, the candidate profit is today's price minus that cheapest.
  3. Keep the best candidate; update the cheapest.
  4. Return the best, which is 0 if prices only fall.
BRUTEO(n²)
OPTIMALO(n)
↕ SCROLL
int maxProfit(vector<int>& p) {
    int best = 0, cheapest = p[0];       // no table, no state
    for (int i = 1; i < (int)p.size(); i++) {
        best = max(best, p[i] - cheapest);   // sell today at the best buy so far
        cheapest = min(cheapest, p[i]);
    }
    return best;                          // floored at 0: doing nothing is legal
}
TIMEO(n)one pass over the days
SPACEO(1)two scalars
TRAP

Returning a negative number when prices only fall. Doing nothing is always an option, so the answer is 0 — and every later problem's 'not holding' state starts at 0 for the same reason.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
68 / INTRO UNIT 12 · THE HOLDING FLAG

UNIT 12 — THE HOLDING FLAG

The flag, and the two moves it permits

THE QUESTION THIS LECTURE ANSWERS

UNLIMITED TRANSACTIONS, ONE SHARE AT A TIME. WHAT DOES THE STATE HAVE TO REMEMBER?

holding flagstate designgreedy exchange
WHAT TO WATCH FOR
  • 01THE STATE IS DAY PLUS A HOLDING FLAG — NOT THE PRICE YOU PAID
  • 02HOLDING: SELL OR KEEP. NOT HOLDING: BUY OR WAIT. PICK / NOT-PICK AGAIN
  • 03A NEGATIVE CELL IS MONEY SPENT, NOT A BUG
  • 04GREEDY (SUM EVERY RISE) WORKS HERE ONLY — THE NEXT ROW BREAKS IT
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
69 / VIDEO UNIT 12 · THE HOLDING FLAG

DP 36 · Buy and Sell Stock II

STRIVER A2Z
The holding flag · two moves per state · the greedy that works here and dies next
RUNTIME 35:34
AFTER THIS → 3 DRILLS · PROBLEM #12
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
70 / DRILL UNIT 12 · THE HOLDING FLAG · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Unlimited transactions, but you may hold at most one share. What does the state become?

Two states per day, and the flag decides which two moves are legal: holding lets you sell or wait; not holding lets you buy or wait. Carrying the BUY PRICE instead would make the state unbounded — the flag is what keeps it O(n).

DRILL 02 · RECALL

You are holding a share on day i. Which two moves are available?

Exactly two, and this is pick / not-pick wearing a different word. Both branches are evaluated and the max kept, which is why the whole family is a DP rather than a scan — even though this particular row also has a one-line greedy answer.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
71 / DRILL UNIT 12 · THE HOLDING FLAG · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

There is a greedy one-liner for this row: sum every positive day-to-day difference. Why does it work here?

With no transaction limit, buying at every local minimum and selling at every local maximum is achievable, and that sum equals the total of positive deltas. Add a cap on transactions — the very next row — and the argument collapses, which is exactly why #13 needs the table.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
72 / MECHANISM UNIT 12 · STOCKS · CODE MIRRORED

THE WHOLE STATE IS ONE FLAG

Prices [7, 1, 5, 3, 6, 4]. Two rows, not holding and holding, and the day walking across. A negative cell is money spent, not a bug. Watch the flag flip: every later row in this section adds exactly one thing to this table and nothing else.

RECURRENCE
STATE
CODE MIRROR
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
73 / PROBLEM #12 · STOCKS · MED

Best time to buy and sell stock II

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

“As many transactions as you like”, but at most one share held. The phrase 'at most one share' is what introduces the state.

INTUITION

Two states per day: holding, or not. Holding lets you sell or keep; not holding lets you buy or wait. Carrying the BUY PRICE instead of a flag would make the state as large as the array — the profit already accounts for what you paid, so the price does not need remembering.

STEPS
  1. State: f(day, holding).
  2. Not holding: max(wait, sell today for +price).
  3. Holding: max(keep, buy today for −price).
  4. Base: day 0 not holding is 0; day 0 holding is −prices[0].
  5. The answer is the not-holding state on the last day — never end holding.
BRUTEO(2ⁿ)
OPTIMALO(n)
↕ SCROLL
int maxProfit(vector<int>& p) {
    int free = 0, hold = -p[0];
    for (int i = 1; i < (int)p.size(); i++) {
        int pf = free, ph = hold;
        free = max(pf, ph + p[i]);        // wait, or SELL
        hold = max(ph, pf - p[i]);        // keep, or BUY
    }
    return free;                          // never end holding a share
}
TIMEO(n)two states per day
SPACEO(1)two scalars
TRAP

Putting the purchase price into the state. It turns 2n cells into n², which is fatal at n = 10⁵ — and it is unnecessary, because a negative running profit already encodes exactly what was spent.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
74 / INTRO UNIT 13 · AT MOST TWO

UNIT 13 — AT MOST TWO

A cap, and why greedy stops working the moment one exists

THE QUESTION THIS LECTURE ANSWERS

AT MOST TWO TRANSACTIONS. WHICH RISES ARE WORTH SPENDING ONE ON?

transaction capthird dimensiongreedy failure
WHAT TO WATCH FOR
  • 01A THIRD INDEX COUNTING TRANSACTIONS LEFT — NOTHING ELSE MOVES
  • 02THE COUNTER DECREMENTS ON THE SELL, WHEN A TRANSACTION COMPLETES
  • 03THE GREEDY FROM THE LAST ROW DIES HERE: YOU MUST CHOOSE WHICH RISES TO BUY
  • 04THE TABLE IS n × 2 × 3 — STILL LINEAR, WHICH IS WHY THE SHEET SAYS MEDIUM
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
75 / VIDEO UNIT 13 · AT MOST TWO

DP 37 · Buy and Sell Stocks III

STRIVER A2Z
The third index · when the counter decrements · the table stays linear
RUNTIME 31:50
AFTER THIS → 3 DRILLS · PROBLEM #13
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
76 / DRILL UNIT 13 · AT MOST TWO · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

At most two transactions. What does the state gain over the previous row?

Day, holding flag, and a cap counter — three indices. The greedy from #12 dies here because capturing every rise may use more than two transactions, so you must choose which rises are worth spending a transaction on.

DRILL 02 · RECALL

When is the transaction counter decremented?

A buy-and-sell pair is one transaction, so decrementing on either would be consistent — but decrementing on the sell means an unsold share never consumes the budget, which matches how the constraint reads. Decrementing on BOTH is the real bug and it halves your allowance.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
77 / DRILL UNIT 13 · AT MOST TWO · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

The state is (day, holding, capLeft). How large is the table?

Two boolean states and three cap values gives 6n cells — still linear, which is why the sheet is comfortable calling this Medium. Recognising that a small extra dimension does not change the complexity class is the point of the row.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
78 / PROBLEM #13 · STOCKS · MED

Best time to buy and sell stock III

MED stocks ▶ SOLVE ON LEETCODESheet says MED, LeetCode says Hard — the widest gap in this deck. The sheet is reasonable IF you have done #12 first: the only change is a third index counting transactions left. Arriving cold, it is a Hard.
SIGNAL — WHAT GIVES IT AWAY

“At most two transactions.” A cap on how many trades — and the moment a cap exists, the greedy from the previous row stops being correct.

INTUITION

Add a third index counting transactions remaining. The greedy 'capture every rise' fails because capturing every rise may take more than two trades, so you must choose which rises are worth spending one on — and choosing is what a table does. The counter decrements on the sell, when a transaction actually completes.

STEPS
  1. State: f(day, holding, capLeft).
  2. Buying is legal while capLeft > 0; it does not consume the cap.
  3. Selling consumes one: capLeft decreases.
  4. Base: no days left, or no cap left, is 0 profit.
  5. The table is n × 2 × 3 — still linear in n.
BRUTEO(2ⁿ)
OPTIMALO(n)
↕ SCROLL
int maxProfit(vector<int>& p) {
    int n = p.size(), K = 2;
    // dp[hold][capLeft] - the cap dimension is the whole addition
    vector<vector<int>> dp(2, vector<int>(K + 1, 0));
    for (int c = 0; c <= K; c++) dp[1][c] = -1e9;
    for (int i = 0; i < n; i++) {
        auto nxt = dp;
        for (int c = 1; c <= K; c++) {
            nxt[1][c] = max(dp[1][c], dp[0][c] - p[i]);        // buy
            nxt[0][c-1] = max(nxt[0][c-1], dp[1][c] + p[i]);   // SELL: cap--
        }
        dp = nxt;
    }
    return max({dp[0][0], dp[0][1], dp[0][2]});
}
TIMEO(n)six states per day
SPACEO(1)a 2 × 3 table, rolled
TRAP

Decrementing the cap on the buy AND the sell. A buy-and-sell pair is one transaction, so charging twice halves your allowance — and the answer is merely lower, never obviously broken.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
79 / INTRO UNIT 14 · AT MOST K

UNIT 14 — AT MOST K

A constant becoming a parameter, for free

THE QUESTION THIS LECTURE ANSWERS

NOW THE CAP IS k INSTEAD OF 2. HOW MUCH OF THE CODE CHANGES?

generalisationparameterisationdegenerate case
WHAT TO WATCH FOR
  • 01THE HARD-CODED 2 BECOMES k. THAT IS THE ENTIRE LECTURE
  • 02TWELVE MINUTES, BECAUSE A CONSTANT BECAME A PARAMETER
  • 03COMPLEXITY GOES O(n·k) — ONE MORE DIMENSION, ONE MORE FACTOR
  • 04WHEN k ≥ n/2 THE CAP CAN NEVER BIND AND IT COLLAPSES TO UNLIMITED
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
80 / VIDEO UNIT 14 · AT MOST K

DP 38 · Buy and Sell Stock IV

STRIVER A2Z
The generalisation · O(n·k) · the k ≥ n/2 collapse
RUNTIME 12:24
AFTER THIS → 3 DRILLS · PROBLEM #14
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
81 / DRILL UNIT 14 · AT MOST K · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Transactions capped at k rather than 2. What changes in the code?

A twelve-minute lecture, because a constant became a parameter. Exactly the Frog Jump to Frog Jump-with-K move from deck I — and recognising that a generalisation is free is worth as much as being able to do it.

DRILL 02 · RECALL

What is the complexity now?

n days × 2 holding states × k caps. Worth noticing that when k ≥ n/2 the cap can never bind, so the problem degenerates to the unlimited case — a real optimisation and a real interview follow-up.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
82 / DRILL UNIT 14 · AT MOST K · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Why does this deck ship it as a DIFF against problem #13 rather than in full?

A delta shows what a generalisation costs — almost nothing — where two full listings would hide it in duplicated code. The deck reserves diffs for exactly this: a change small enough that seeing only the change is more informative than seeing the whole.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
83 / PROBLEM #14 · STOCKS · MED

Best time to buy and sell stock IV

MED stocks ▶ SOLVE ON LEETCODEProblem #13 with the hard-coded 2 replaced by k. One constant becomes a parameter and nothing else moves — the same generalisation deck I made from Frog Jump to Frog Jump with K.
SIGNAL — WHAT GIVES IT AWAY

The previous problem with the 2 replaced by a parameter k. A constant becoming a parameter always means the loop was already there.

INTUITION

Nothing about the recurrence changes — the cap dimension simply runs to k rather than to 2. Worth knowing the degenerate case: once k ≥ n/2 the cap can never bind, because there are not enough days to make that many trades, and the problem collapses to the unlimited version.

STEPS
  1. State is unchanged: f(day, holding, capLeft), with capLeft up to k.
  2. If k ≥ n/2, fall back to problem #12 — the cap cannot bind.
  3. Otherwise run the same transitions as #13.
  4. The table is n × 2 × (k+1).
BRUTEO(2ⁿ)
OPTIMALO(n·k)
-int maxProfit(vector<int>& p) {-    int n = p.size(), K = 2;-    // dp[hold][capLeft] - the cap dimension is the whole addition+int maxProfit(int K, vector<int>& p) {+    int n = p.size();+    if (n == 0 || K == 0) return 0;     vector<vector<int>> dp(2, vector<int>(K + 1, 0));     for (int c = 0; c <= K; c++) dp[1][c] = -1e9;     for (int i = 0; i < n; i++) {         auto nxt = dp;         for (int c = 1; c <= K; c++) {-            nxt[1][c] = max(dp[1][c], dp[0][c] - p[i]);        // buy-            nxt[0][c-1] = max(nxt[0][c-1], dp[1][c] + p[i]);   // SELL: cap--+            nxt[1][c] = max(dp[1][c], dp[0][c] - p[i]);+            nxt[0][c-1] = max(nxt[0][c-1], dp[1][c] + p[i]);         }         dp = nxt;     }-    return max({dp[0][0], dp[0][1], dp[0][2]});+    return *max_element(dp[0].begin(), dp[0].end()); }
TIMEO(n·k)2(k+1) states per day
SPACEO(k)one 2 × (k+1) table, rolled
TRAP

Allocating the table before checking k. A judge may hand you k = 10⁹ with n = 10³, and a k-sized dimension blows memory instantly — where the k ≥ n/2 shortcut answers it in linear time.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
84 / INTRO UNIT 15 · COOLDOWN

UNIT 15 — COOLDOWN

A constraint expressed as a longer reach

THE QUESTION THIS LECTURE ANSWERS

AFTER SELLING YOU MUST SIT OUT A DAY. WHERE DOES THAT GO IN THE RECURRENCE?

cooldownreachconstraint placement
WHAT TO WATCH FOR
  • 01THE BUY BRANCH READS DAY i−2, NOT i−1 — THAT IS THE COOLDOWN
  • 02GUARD i−2 ON THE FIRST TWO DAYS. THE SAME OFF-BY-ONE AS FROG JUMP
  • 03THE COOLDOWN APPLIES AFTER A SALE ONLY, NEVER AFTER A BUY
  • 04AN EXTRA STATE WOULD ALSO WORK — THE TWO-DAY REACH IS JUST SHORTER
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
85 / VIDEO UNIT 15 · COOLDOWN

DP 39 · Buy and Sell Stocks With Cooldown

STRIVER A2Z
Buying looks back two days · guarding i−2 · the constraint applies to sales only
RUNTIME 15:21
AFTER THIS → 3 DRILLS · PROBLEM #15
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
86 / DRILL UNIT 15 · COOLDOWN · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

After selling you must skip a day. How is that expressed in the recurrence?

Selling on day i−1 means you cannot buy on day i, so buying looks back two days instead of one. A separate cooldown state also works and is what many write-ups do; the two-day reach is the shorter expression of the same rule.

DRILL 02 · RECALL

Which index must be guarded once the buy branch reaches back two days?

Precisely the guard deck I put on Frog Jump's two-step branch — the same off-by-one, three decks apart, because the same thing causes it: a recurrence that reaches further back than the array has room for.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
87 / DRILL UNIT 15 · COOLDOWN · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Does the cooldown apply after BUYING as well as after selling?

The constraint is stated for sales alone. Applying it to buys as well is a misreading that produces a lower, entirely believable profit — the kind of wrong answer that comes from skimming the statement rather than from bad code.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
88 / PROBLEM #15 · STOCKS · MED

Best Time to Buy and Sell Stock with Cooldown

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

“After you sell, you cannot buy the next day.” A constraint that reaches across days rather than adding a new decision.

INTUITION

Selling on day i−1 forbids buying on day i. So the buy branch looks back two days instead of one, and everything else is problem #12 unchanged. A separate 'cooldown' state also works; the two-day reach is the shorter way of saying the same thing — and it needs the same i−2 guard Frog Jump needed in deck I.

STEPS
  1. State: f(day, holding), same as #12.
  2. Selling: as before, from the holding state.
  3. Buying: read the not-holding state from day i+2 (working backwards), not i+1.
  4. Guard the two days at the boundary.
  5. Note the cooldown applies after a SALE only, never after a buy.
BRUTEO(2ⁿ)
OPTIMALO(n)
↕ SCROLL
int maxProfit(vector<int>& p) {
    int n = p.size();
    vector<int> free(n + 2, 0), hold(n + 2, -1e9);
    hold[n] = hold[n+1] = -1e9;
    for (int i = n - 1; i >= 0; i--) {
        free[i] = max(free[i+1], hold[i+1] + p[i]);   // wait, or SELL
        // after BUYING, you could only have been free since i+2 - the COOLDOWN
        hold[i] = max(hold[i+1], free[i+2] - p[i]);
    }
    return free[0];
}
TIMEO(n)two states per day
SPACEO(1)three scalars for the two-day reach
TRAP

Applying the cooldown after buying as well. The statement restricts sales only, and the stricter reading gives a lower, entirely plausible profit — a misreading rather than a bug, which is why it survives code review.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
89 / INTRO UNIT 16 · A FEE PER TRADE

UNIT 16 — A FEE PER TRADE

A change to a value, not to a state

THE QUESTION THIS LECTURE ANSWERS

EVERY COMPLETED TRADE COSTS A FEE. DOES THE STATE HAVE TO GROW?

feevalue vs stategreedy failure
WHAT TO WATCH FOR
  • 01SUBTRACT THE FEE ONCE, ON THE SELL — CHARGING BOTH HALVES DOUBLE-COUNTS
  • 02THE STATE IS IDENTICAL TO UNLIMITED TRANSACTIONS. NOTHING IS ADDED
  • 03A CHANGE TO A VALUE, NOT TO A MEANING — THAT DISTINCTION IS STATE DESIGN
  • 04GREEDY DIES AGAIN: SMALL RISES CAN BE WORTH LESS THAN THE FEE
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
90 / VIDEO UNIT 16 · A FEE PER TRADE

DP 40 · Buy and Sell Stocks With Transaction Fee

STRIVER A2Z
The fee on the sell · why the state is unchanged · why greedy fails again
RUNTIME 7:20
AFTER THIS → 3 DRILLS · PROBLEM #16
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
91 / DRILL UNIT 16 · A FEE PER TRADE · 1 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

A fee is charged per completed transaction. Where does it go in the recurrence?

One fee per completed transaction, and a transaction completes at the sell — so subtract it there and the state does not grow at all. Charging on both halves double-counts and quietly halves your profit on fee-heavy inputs.

DRILL 02 · RECALL

How does the state compare with problem #12, unlimited transactions?

The fee changes a VALUE, not a state — which is why this is the gentlest row in the section despite arriving last. Distinguishing 'this changes what a cell is worth' from 'this changes what a cell means' is the whole skill of state design.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
92 / DRILL UNIT 16 · A FEE PER TRADE · 2 OF 2

CHECK — CAN YOU ANSWER IT WITHOUT LOOKING BACK?

DRILL 01 · RECALL

Why does the greedy 'sum every positive difference' fail once a fee exists?

Several small rises that were each profitable individually can be worth less than one longer hold once the fee is charged per trade. The table weighs holding against trading automatically; greedy has to be told, and cannot be told locally.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
93 / PROBLEM #16 · STOCKS · MED

Best time to buy and sell stock with transaction fees

MED stocks ▶ SOLVE ON LEETCODEProblem #12 with the fee subtracted once per completed transaction. The state does not grow at all — which is what makes it the gentlest row in the section and a good one to end on.
SIGNAL — WHAT GIVES IT AWAY

“A fee for each transaction.” Note what this does NOT add: no cap, no cooldown, no extra index. The state is untouched.

INTUITION

Subtract the fee once, at the point a transaction completes — the sell. The state does not grow at all, because the fee changes what a cell is WORTH rather than what it MEANS. That distinction is the whole of state design, and this is the cleanest example of it in the deck.

STEPS
  1. State: f(day, holding), identical to #12.
  2. Selling: +price − fee.
  3. Buying: −price, unchanged.
  4. Return the not-holding state on the last day.
BRUTEO(2ⁿ)
OPTIMALO(n)
↕ SCROLL
int maxProfit(vector<int>& p, int fee) {
    int free = 0, hold = -p[0];
    for (int i = 1; i < (int)p.size(); i++) {
        int pf = free, ph = hold;
        free = max(pf, ph + p[i] - fee);   // the fee is charged ONCE, here
        hold = max(ph, pf - p[i]);
    }
    return free;
}
TIMEO(n)two states per day
SPACEO(1)two scalars
TRAP

Charging the fee on both the buy and the sell. One trade is one fee; charging twice quietly halves the profit on fee-heavy inputs and leaves it correct when the fee is 0 — which is exactly the test case people check.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
94 / RECALL RETRIEVAL, NOT RECOGNITION · 1 OF 3

NAME THE TABLE FROM WHAT IS ASKED

DRILL 01 · RECALL

A mismatch in longest common SUBSTRING sets the cell to…

Zero, always. Consecutiveness means an interrupted run cannot continue, so nothing is inherited. Inheriting a neighbour is precisely the LCS behaviour, and it is the single cell of difference between the two problems.

DRILL 02 · RECALL

Longest palindromic subsequence of s is computed how?

A palindrome is common to s and reverse(s), and any subsequence common to both reads the same either way. Minimum insertions to make s a palindrome then falls out as n minus this — two problems solved by one reversal and no new recurrence.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
95 / RECALL RETRIEVAL, NOT RECOGNITION · 2 OF 3

NAME THE TABLE FROM WHAT IS ASKED

DRILL 01 · RECALL

Converting A to B with insertions and deletions only costs…

Two leftovers. Delete what A has beyond the LCS, insert what B has beyond it. Subtracting the LCS only once gives the SHORTEST COMMON SUPERSEQUENCE's length instead — the same three quantities rearranged, which is why the two get confused.

DRILL 02 · RECALL

Distinct Subsequences: characters match. What does the transition do?

This is the one table where a match is not forced. That source character can serve this target character or be saved for a later one, and both produce valid distinct subsequences — so both count and they add. Every other string problem here banks a match unconditionally.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
96 / RECALL RETRIEVAL, NOT RECOGNITION · 3 OF 3

NAME THE TABLE FROM WHAT IS ASKED

DRILL 01 · RECALL

Wildcard matching: the pattern character is *. What are the branches?

OR the two. Staying on the star while consuming one more character is the same stay-put move unbounded knapsack used in deck II — and it is the branch that lets one star cover any length. Forgetting the empty case fails on the shortest inputs.

DRILL 02 · RECALL

Stock problems: what does adding a cap of k transactions do to the complexity?

One more dimension, one more factor. Still polynomial and still cheap. Worth knowing the corollary too: once k ≥ n/2 the cap can never bind, so the problem collapses to the unlimited case — a genuine optimisation and a standard follow-up question.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
97 / TRAPS PLAUSIBLE, WRONG, AND SILENT

SIX WAYS TO BE PLAUSIBLY WRONG

Every one of these returns a number. Three of them return a number that is merely too small, which is the hardest kind to notice — the code runs, the samples pass, and the judge disagrees on a case you never thought to try.

CHARGING FOR A MATCH IN EDIT DISTANCE

if (a[i-1]==b[j-1]) return 1 + f(i-1,j-1);. A match is free. The 1 inflates every answer by exactly the LCS length — plausible, monotonic in the input, and wrong.

INHERITING A NEIGHBOUR IN LONGEST COMMON SUBSTRING

A mismatch must reset the cell to 0. Take max(up, left) instead and you have silently written LCS, which returns a longer answer for a question about consecutive runs.

READING THE CORNER FOR A SUBSTRING ANSWER

Each cell is a run ENDING there, so the best run may end anywhere. The bottom-right cell is the run ending at both string ends — usually 0, occasionally right by accident.

SUBTRACTING THE LCS TWICE, OR ONCE, IN THE WRONG PLACE

Insert-and-delete cost is n + m − 2·LCS; the shortest common supersequence is n + m − LCS. The same three numbers answer two different questions and swapping them never crashes.

TREATING A MATCH AS FORCED IN DISTINCT SUBSEQUENCES

Taking only the diagonal on a match undercounts, because that source character could have been saved for a later target character. The answer is smaller and entirely believable.

REMEMBERING THE BUY PRICE IN A STOCK STATE

It turns 2n states into n², and for n = 10⁵ that is fatal. The profit already accounts for what was paid; a boolean holding flag is all the state the problem needs.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
98 / CHEATSHEET REVISION SURFACE

ONE SCREEN, THE WHOLE DECK

Fifteen rows, two tables. Everything above the line is the LCS grid read differently; everything below it is one array and a flag.

ALGORITHM
TIME
SPACE
REACH FOR IT WHEN
Longest common subsequence
O(n·m)
O(m)
match: 1+diag · else: max(up, left)
Print the LCS
O(n·m)
O(n·m)
fill, then walk backwards from the corner; reverse it
Longest common substring
O(n·m)
O(m)
mismatch resets to 0; answer is the largest cell
Longest palindromic subsequence
O(n²)
O(n)
LCS(s, reverse s)
Min insertions for a palindrome
O(n²)
O(n)
n − LPS(s)
Min insert+delete, A to B
O(n·m)
O(m)
(n − LCS) + (m − LCS)
Shortest common supersequence
O(n·m)
O(n·m)
length n + m − LCS; build by walking back
Distinct subsequences
O(n·m)
O(m)
match: diag + skip (ADD) · else: skip
Edit distance
O(n·m)
O(m)
match: free · else: 1 + min(ins, del, rep)
Wildcard matching
O(n·m)
O(m)
'*': OR(skip star, consume one and stay)
Stock · one transaction
O(n)
O(1)
track the minimum price so far — no table
Stock · unlimited
O(n)
O(1)
free = max(free, hold+p) · hold = max(hold, free−p)
Stock · at most k
O(n·k)
O(k)
add a cap index; decrement on the SELL
Stock · cooldown
O(n)
O(1)
the buy branch reads day i−2, not i−1
Stock · transaction fee
O(n)
O(1)
subtract the fee once, on the sell
INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
99 / CLOSE STEP 16 · DECK 3 OF 4

MATCH OR MOVE ON

Ten string problems and one table: characters match, so bank them and step diagonally; they do not, so try both drops and keep the better. Change the mismatch to a zero and it counts consecutive runs; feed it a reversed string and it finds palindromes; subtract its answer from the lengths and it prices insertions and deletions. Then six stock problems that abandon the second string entirely and carry a flag instead — holding or not, transactions left, one day of cooldown, a fee. Deck IV is the last one: subsequences that must increase, and the partition DP where you choose where to CUT rather than what to take.

00%
OF THIS DECK SOLVED
← ALL TOPICSTHE SHELFDECK II · SUBSEQUENCES

Deck 3 of 4. Lectures DP 25-40 of 56, sixteen against sixteen sheet rows — the only exactly one-to-one slice in the playlist. Every drill cites its lecture transcript; every bench fills in numbers the build re-derived; and every code listing in this deck was executed against the judge's own examples before it shipped.

INVARIANT · DYNAMIC PROGRAMMING · STRINGS & STOCKS · DECK 3 OF 4
■ TOO SMALL TO READ
1280×720
INVARIANT · STEP 16 · DECK 3 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
TWO CURSORS · OR A STATE YOU CARRY
Your progress is saved per device, so anything you tick on the laptop will be waiting there.