Pattern

Dynamic programming

Break a problem into overlapping subproblems, solve each once, and reuse the results to build the final answer.

What it is

Dynamic programming solves a problem by expressing its answer in terms of the answers to smaller versions of itself, then filling those smaller answers in once — bottom-up in a table or top-down with memoization — instead of recomputing them on every branch of a recursion. The state is usually a small number of indices or a small remaining budget (a position in a string, a prefix of two strings, a remaining sum), and the payoff is turning an exponential number of possibilities into a table you can fill in polynomial time. Most solutions also collapse to O(1) or O(n) extra space once you notice the recurrence only reaches back one or two rows.

When it applies

Tells in the problem

The classic mistake

The most common failure is writing the correct recurrence but re-deriving each subproblem from scratch with plain recursion, with no memo table and no bottom-up order — the code looks right on a tiny example and then blows up in time or hits recursion-depth limits on real input. This happens because the recurrence itself is genuinely the hard part to find, so once it's written it's tempting to treat the implementation as an afterthought. Catch it by asking, before you write a single line of code, "how many distinct subproblems exist, and in what order do I need their answers?" — if you can't answer that, you don't yet have a DP, you have a recursion.

Questions to start with

All 34 dynamic programming questions

Problem statement, examples and hints are free on every page; the worked approach, solution and tests are in the company guides.

Free starter pack

13 must-tier questions with full solutions

Sign in with an email — no purchase — and read them in the full reader.

No password, no spam. One sign-in email; you can read the pack in the full reader.