interviewpath
  • 0day streak
  • 10total XP
  • Level 1
0/6

Unit 1 · Algorithms · Lesson 19 of 24

Dynamic programming foundations

Dynamic programming solves problems whose subproblems overlap by computing each subproblem once, in an order where its dependencies are ready. Interviewers use it to test whether you can define a state precisely, derive a recurrence and turn it into correct, efficient code, not whether you remember a particular table.
About 6 hFocus mode

Step 1: Learn the ideas

  • Overlapping subproblems and optimal substructure
  • State definition and the SRTBOT checklist
  • Transitions by case analysis on the last decision
  • Base cases and identity values
  • Top-down memoization and recursion limits
  • Bottom-up tabulation and evaluation order
  • DP as a DAG of subproblems
  • Reconstructing the solution
  • Space optimization with rolling variables
  • Prefix DPs: decoding and word-break style problems

Why it matters

Dynamic programming turns exponential search into polynomial time whenever the same subproblems recur. In interviews it matters as much for what it reveals as for the problems themselves: can you define what a subproblem means, argue that a recurrence covers every case, and avoid the initialization and off-by-one bugs that DP code invites? Outside interviews the pattern appears in edit distance and sequence alignment, Viterbi decoding, join-order selection in query optimizers and resource allocation, anywhere results of subcomputations can be reused.

Core ideas

MIT 6.006 frames DP design as a checklist (SRTBOT) that is worth saying aloud:

  • Subproblems: a precise definition, such as "best[i] is the maximum total from the first i houses". Most DP bugs trace back to a vague state.
  • Relate: compute a subproblem from smaller ones by case analysis on one decision: either house i-1 is robbed or it is not, so best[i] = max(best[i-1], best[i-2] + value[i-1]).
  • Topological order: an order in which dependencies are ready, here increasing i. If none exists, the recurrence has a cycle and is not well founded.
  • Base cases: best[0] = 0 and best[1] = value[0].
  • Original problem: best[n].
  • Time: number of states times work per state, here O(n).

A relation is complete when the cases for the decision are exhaustive, and for counting they must also be disjoint. Counting ordered sequences when the problem wants unordered combinations is a typical failure of that test.

Top-down versus bottom-up. Memoization wraps the brute-force recursion with a cache: it is easy to derive and evaluates only reachable states, but its recursion depth equals the longest dependency chain, and deep chains exceed Python's default recursion limit of 1000 frames. Tabulation fills an array in a topological order: no recursion and easy space optimization, but you must find the order and you compute every state. Asymptotic time is the same.

from functools import cache

def min_coins(coins, amount):
    @cache
    def f(a):                      # fewest coins summing to exactly a
        if a == 0:
            return 0
        best = float('inf')
        for c in coins:
            if c <= a:
                best = min(best, f(a - c) + 1)
        return best
    result = f(amount)
    return -1 if result == float('inf') else result

The bottom-up version is a loop over a from 1 to amount; it avoids the depth problem when amount is large.

DP as a DAG. States are vertices and transitions are edges; the answer is a shortest, longest or counted path. This view explains why a valid evaluation order is a topological order and why the running time is proportional to the number of transitions.

Reconstruction. Store which choice achieved each optimum, or recompute it by checking which transition matches the stored value, then walk back from the original problem. Interviewers often ask for the items, not just the number.

Space optimization. If state i depends only on i-1 and i-2, keep two variables. Do this after the full version is correct, because reconstruction usually needs the full table or a parent array.

Identity values. Counting uses 0 for impossible and 1 for the empty way; minimization uses infinity for impossible; feasibility uses booleans. Mixing them up causes wrong answers on edge cases such as an amount of 0.

Common misconceptions

  • "DP means filling a table." The table is an implementation detail; the state definition and recurrence are the solution. Say them before coding.
  • "Memoization is slower than tabulation." They match asymptotically; memoization pays call overhead and recursion depth, tabulation computes states that may be unreachable. Choose by clarity and constraints.
  • "Adding a cache to any recursion makes it efficient." Only if the number of distinct states is small; caching on a huge or unbounded state, such as a whole remaining list, does not help.
  • "If greedy fails, the problem is hopeless." It usually means choices interact, which is exactly where a DP over the right state works.
  • "Space optimization is always safe." It discards what reconstruction needs, and with the wrong loop order it reads values that were already overwritten.

How to approach it

Start from a correct brute-force recursion that makes one decision per call; its parameters become the state. Count states and work per state to get the complexity before adding the cache. Then choose top-down or bottom-up, write base cases first, and hand-run the smallest non-trivial input. Interviewers at every level expect a clearly stated state and recurrence; stronger candidates explain why the cases are exhaustive, reconstruct the solution, and optimize space only after correctness is established.

Suggested order

  1. 1Read MIT 6.006 Lecture 15 (Dynamic Programming, Part 1) for the SRTBOT framework, memoization and the subproblem DAG; skim Recitation 15 for top-down versus bottom-up implementation.
  2. 2Read Erickson Ch. 3 (Dynamic Programming), the sections "The Pattern: Smart Recursion" and "Warning: Greed is Stupid".
  3. 3Solve Climbing Stairs and Min Cost Climbing Stairs three ways: plain recursion (observe the blow-up), memoized, and bottom-up with two variables.
  4. 4Solve House Robber and House Robber II; write the one-sentence state definition before any code and reconstruct which houses were chosen.
  5. 5Solve Coin Change, Decode Ways and Word Break; for each, list the base cases and the identity value (0, 1, infinity or false).
  6. 6Solve Longest Increasing Subsequence in O(n^2), then study the O(n log n) variant and explain its invariant.
  7. 7Use Maximum Product Subarray and Best Time to Buy and Sell Stock with Cooldown for review rotation: both need more than one value per index.

Step 2: Check off what you can do

Tap each one you can genuinely do or explain. Each earns 10 XP.

Step 3: Go deeper

  • MIT 6.006 Introduction to Algorithms (Spring 2020)Start here

    MIT OpenCourseWare

    Section: Lecture 15: Dynamic Programming, Part 1

    The SRTBOT design checklist, memoization, subproblem DAGs and parent pointers for reconstruction; Recitation 15 contrasts top-down and bottom-up.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • Algorithms (Jeff Erickson) with companion lecture notesStart here

    Jeff Erickson, University of Illinois Urbana-Champaign

    Section: Ch. 3: Dynamic Programming

    Deriving DPs as smart recursion: define the recursive structure first, then memoize and choose an evaluation order.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • Competitive Programmer’s Handbook

    CSES

    Section: Ch. 7: Dynamic programming

    Short, code-level walkthroughs of coin problems, longest increasing subsequence and grid paths, including solution reconstruction.

    Open(opens in a new tab)Link responded, 5 Oct 2026

Step 4: Practice

Write the state definition, relation, base cases and complexity in four lines before coding each problem; if you cannot, you are not ready to code. Solve the first two in all three styles (plain recursion, memoization, tabulation). Treat the last items as review rotation; they need a state with more than one value per index.

Record attempts on each problem’s page (+15 XP, +10 more when solved on your own).

Step 5: Test yourself

Answer each one out loud or on paper before you finish the lesson.

  1. Question 1What exactly does your state mean, and does it capture everything that future decisions depend on?
  2. Question 2Why must the evaluation order be a topological order of the subproblem DAG?
  3. Question 3How do you compute the running time of a memoized recursion?
  4. Question 4Which identity value represents "impossible" in a minimization DP, and which represents "one way" in a counting DP?
  5. Question 5How would you return the chosen items instead of the optimal value?
  6. Question 6When does replacing the table with two variables break reconstruction?

You’re done when you can

  • For any practice problem, state the subproblem, relation, base cases and complexity in under three minutes without notes.
  • Convert a given exponential recursion into memoized and bottom-up versions in under 20 minutes.
  • Solve one unseen one-dimensional DP problem in under 30 minutes and reconstruct the chosen elements.
  • Explain when top-down is preferable to bottom-up and vice versa, with one concrete reason each.

Finish the lesson

How confident do you feel?

Lesson complete!

+50 XP

Reviews will come up on the Practice tab so it sticks.

Unlocks next: Dynamic programming on sequences, grids and knapsacks, Pattern recognition and mixed practice

Your notes and study time

Log study time