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 pageshowhide
explore
- Recognizing DP Problems8 questions
- DP vs Divide-and-Conquer vs Greedy4 questions
- Implementation Approaches16 questions
- Top-Down Memoization vs Bottom-Up Tabulation4 questions
- State, Transitions & Base Cases4 questions
- Space Optimization & Rolling Arrays4 questions
- Complexity of DP Solutions4 questions
- Problem Archetypes37 questions
- 1D Sequence DP4 questions
- Knapsack Family8 questions
- String DP9 questions
- Grid-Path DP4 questions
- Advanced DP Patterns12 questions
- Computer Scienceskillanchors this topic
- Data Structures & Algorithmsskillanchors this topic
- AI & Data Scientistrole
- AI Engineerrole
- AI Red Teamingrole
- Android Developerrole
- Backend Developerrole
- Blockchain Developerrole
- Cyber Security Expertrole
- Data Analystrole
- Data Engineerrole
- DevOps / SRE Engineerrole
- DevSecOps Engineerrole
- Forward Deployed Engineerrole
- Frontend Developerrole
- Full Stack Developerrole
- Game Developerrole
- Java Backend Developerrole
- Java SDETrole
- Kotlin Backend Developerrole
- MLOps Engineerrole
- Machine Learning Engineerrole
- Network Engineerrole
- PostgreSQL DBArole
- QA Engineerrole
- Software Architectrole
- iOS Developerrole
questions
61 · 3 sectionsIn dynamic programming, what does 'overlapping subproblems' mean, and how does naive recursive Fibonacci show it?
basics
~20 sOverlapping 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.
When does adding a memo table to a divide-and-conquer recursion buy you nothing?
basics
~20 sMemoization 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.
How would you prove a cheapest multi-leg travel itinerary has optimal substructure?
basics
~20 sA 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.
Why doesn't a greedy rule passing every test case you tried prove it optimal?
basics
~20 sPassing 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.
Why does longest simple path lack optimal substructure when shortest path has it?
basics
~20 sThe 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.
Why does memoizing an exponential recursion change its time complexity, and to what?
basics
~20 sMemoization 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.
Memoized recursion vs a bottom-up DP table: what actually differs between them?
basics
~20 sBoth 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.
Why can a bottom-up DP that fills a 2D table often keep only two rows in memory?
basics
~20 sOnly 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.
What should dp[0] hold in a bottom-up DP table indexed by items considered so far?
basics
~20 sdp[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].
Why is a DP that fills an n x K table with an inner scan over earlier positions not O(n*K)?
basics
~20 sDP 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.
In a right-and-down-only grid, why is a cell's route count the sum of the cells above and left?
basics
~20 sEvery 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.
In 0/1 knapsack, what does dp[i][w] hold and which two candidates does the recurrence compare?
basics
~20 sdp[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.
In minimum-coins change-making, what does dp[a] hold and how do you mark unreachable amounts?
basics
~10 sdp[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.
Why does greedily picking the highest-value non-adjacent ad slots miss the optimal schedule?
basics
~20 sGreedy 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.
In an edit distance table over two contact names, what does dp[i][j] mean and what fills row 0?
basics
~20 sdp[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.