skip to content

Dynamic Programming

Dynamic programming turns exponential brute force into polynomial-time solutions by caching answers to overlapping subproblems. Interviewers lean on DP because it exposes whether you can define a state, justify a recurrence, and analyze the result — not just replay a memorized solution.

part ofData structures & algorithmsoverview, primer and where to startread it →
on this pageshow

questions

61 · 3 sections

In dynamic programming, what does 'overlapping subproblems' mean, and how does naive recursive Fibonacci show it?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Overlapping subproblems means the same subproblem instance, with identical arguments, is solved repeatedly. Naive recursive Fibonacci recomputes the same argument in many separate branches, so distinct subproblems number about n while calls grow far faster.

open as a page

When does adding a memo table to a divide-and-conquer recursion buy you nothing?

level: juniorimportance: must knowfreq 70%
basics
~20 s

Memoization pays only when the same subproblem recurs. A recursion that splits its input into disjoint parts produces a distinct key on every call, so every lookup misses and you pay memory plus bookkeeping for zero saved work.

open as a page

How would you prove a cheapest multi-leg travel itinerary has optimal substructure?

level: middleimportance: must knowfreq 55%
basics
~20 s

A cheapest itinerary's prefix must itself be cheapest: swapping in a cheaper A-to-M portion would make the whole cheaper, contradicting optimality. The argument needs fares to add across the cut and the two portions to be independent.

open as a page

Why doesn't a greedy rule passing every test case you tried prove it optimal?

level: middleimportance: must knowfreq 60%
basics
~20 s

Passing cases shows only that no input you happened to choose exposed the flaw. Greedy optimality is a claim about every input, and it rests on the greedy-choice property: the locally best move must be consistent with some optimal solution.

open as a page

Why does longest simple path lack optimal substructure when shortest path has it?

level: seniorimportance: should knowfreq 40%
basics
~20 s

The pieces are not independent: a longest simple path's prefix need not be longest to that town, and pasting two optimal halves can revisit a town, producing a walk that is not simple. Shortest paths suffer neither failure.

open as a page

Why does memoizing an exponential recursion change its time complexity, and to what?

level: juniorimportance: must knowfreq 82%
basics
~20 s

Memoization computes each distinct subproblem once and reuses the stored result, so cost drops from the number of call paths to (number of distinct states) times (work per transition). It only helps when subproblems actually repeat.

open as a page

Memoized recursion vs a bottom-up DP table: what actually differs between them?

level: juniorimportance: must knowfreq 76%
basics
~20 s

Both evaluate the same recurrence at the same asymptotic cost. Memoization recurses from the goal downward, caching answers on demand and touching only states it can reach. Tabulation fills every state in an order you choose, using no call stack.

open as a page

Why can a bottom-up DP that fills a 2D table often keep only two rows in memory?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Only the cells that a pending transition still reads have to stay in memory. When every value in row i is computed from row i-1 alone, the finished earlier rows are dead weight, so two rows are enough.

open as a page

What should dp[0] hold in a bottom-up DP table indexed by items considered so far?

level: juniorimportance: must knowfreq 68%
basics
~20 s

dp[0] is the empty-prefix answer: zero items considered, not the first item. Seed it with the identity of whatever the transition combines, such as 0 for a sum, 1 for counting the single empty arrangement, or a large sentinel for a minimisation. The first item's result lands in dp[1].

open as a page

Why is a DP that fills an n x K table with an inner scan over earlier positions not O(n*K)?

level: middleimportance: must knowfreq 72%
basics
~20 s

DP time is (number of states) times (cost of one transition), not table size alone. With nK cells and an inner scan of up to n predecessors, the cost is O(n^2K); counting cells hides the inner loop.

open as a page

In a right-and-down-only grid, why is a cell's route count the sum of the cells above and left?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Every route into a cell takes its last step from either the cell above or the cell to its left. Those two sets of routes are disjoint and together cover every route, so the two counts simply add.

open as a page

In 0/1 knapsack, what does dp[i][w] hold and which two candidates does the recurrence compare?

level: juniorimportance: must knowfreq 78%
basics
~20 s

dp[i][w] is the best total value reachable using only the first i items within a capacity of w. The recurrence takes the larger of leaving item i out, dp[i-1][w], and taking it, value[i] + dp[i-1][w - weight[i]], when it fits.

open as a page

In minimum-coins change-making, what does dp[a] hold and how do you mark unreachable amounts?

level: juniorimportance: must knowfreq 78%
basics
~10 s

dp[a] holds the fewest coins summing exactly to amount a: one plus the smallest dp[a - c] over each denomination c that fits. Amounts no combination reaches carry an infinity sentinel, never 0.

open as a page

Why does greedily picking the highest-value non-adjacent ad slots miss the optimal schedule?

level: juniorimportance: must knowfreq 74%
basics
~20 s

Greedy commits to a big slot before knowing what it blocks: taking a slot forbids both neighbours, so two merely good neighbours can outvalue one great slot. The take-or-skip recurrence best(i) = max(best(i-1), value(i) + best(i-2)) weighs both futures.

open as a page

In an edit distance table over two contact names, what does dp[i][j] mean and what fills row 0?

level: juniorimportance: must knowfreq 72%
basics
~20 s

dp[i][j] is the edit distance between the first i characters of one name and the first j of the other — the indexes are prefix LENGTHS, not positions. Row 0 holds 0,1,2,...,j: turning nothing into a j-character prefix costs j insertions.

open as a page