A topic in the Open Knowledge Graph — a free, open map of 15,290 topics and the order to learn them in.

Dynamic Programming

College Depth 88 in the knowledge graph ☐ I know this ☆ Set as goal
149topics build on this
468prerequisites beneath it
See this on the map →
Algorithm Design BasicsRecursion Basics+4 more→→0/1 Knapsack Problem: Bounded Capacity DPBelief Propagation Algorithm+15 more
dynamic-programming DP optimal-substructure overlapping-subproblems

Core Idea

Dynamic programming (DP) solves optimization and counting problems by breaking them into overlapping subproblems and storing solutions to avoid redundant computation. Two key properties must hold: optimal substructure (the optimal solution contains optimal solutions to subproblems) and overlapping subproblems (the same subproblems recur many times). Classic examples include Fibonacci, 0/1 knapsack, longest common subsequence, and coin change. DP transforms exponential naive recursion into polynomial time by caching intermediate results.

How It's Best Learned

Start with memoized Fibonacci to see the speedup from caching in isolation. Then tackle structured DP problems: coin change, longest common subsequence, 0/1 knapsack. For each, explicitly define the subproblem before writing any code.

Common Misconceptions

Explainer

Recursion solves a problem by reducing it to smaller instances of itself. The danger is that naive recursion often recomputes the same smaller instances many times. Consider computing Fibonacci(50) recursively: Fibonacci(3) gets recalculated billions of times because the call tree branches at every level, producing exponential work. Dynamic programming patches this by storing each result the first time it is computed and looking it up instead of recomputing — a technique called memoization.

Two structural properties must hold for DP to apply. Optimal substructure means the solution to the full problem can be assembled from optimal solutions to subproblems. The shortest path from A to C through B must use the shortest path from A to B as a segment — if that sub-path were suboptimal, you could improve the full path, contradicting its optimality. Overlapping subproblems means the same sub-instances appear repeatedly across the recursion tree. Without overlap, caching adds overhead with no benefit; this is why merge sort, which splits arrays into non-overlapping halves, is divide-and-conquer rather than DP.

The hardest part of dynamic programming is not the code — it is defining the subproblem correctly before you write a line. You should be able to state "dp[i] means ___" in a precise sentence. For coin change, the right definition is: "dp[i] = the minimum number of coins needed to make exactly amount i." Given that, the recurrence follows mechanically: dp[i] = 1 + min over all coins c ≤ i of dp[i - c]. A vague definition like "dp[i] represents the coins used so far" produces an ambiguous recurrence and subtle bugs that are very hard to debug.

Once the subproblem is defined, you can implement it two ways. Top-down (memoization): write the natural recursive solution, add a cache (array or hash map), and check the cache before computing. The code reads like the mathematical recurrence and only computes subproblems that are actually needed. Bottom-up (tabulation): fill a table starting from base cases, computing each entry using previously filled entries. This avoids recursion stack overhead and often performs better in practice. Both have the same asymptotic time complexity — they solve each of the O(n) (or O(n²), etc.) subproblems exactly once.

Your background in recurrence relations connects directly: the DP recurrence is that relation made computational. Your knowledge of time-space complexity explains why DP matters — the transformation from exponential naive recursion to polynomial time, achieved by eliminating redundant computation. And mathematical induction provides the proof structure: show the base case, assume all smaller subproblems are solved correctly, and verify the recurrence step is correct. The inductive structure of correctness proofs and the recursive structure of DP are two sides of the same coin.

Practice Questions 3 questions

Prerequisite Chain

Understanding Zero → The Number Zero → Counting to Five → Counting to 10 → Counting to 20 → Counting a Set of Objects Up to 20 → Cardinality: The Last Number Counted → Matching Numerals to Quantities → Subitizing Small Quantities → Addition Within 10 → Number Bonds to 10 → Addition Within 20 → Doubles and Near Doubles → Doubles Facts Within 10 → Near Doubles Facts Within 20 → Mental Math Strategies for Addition → Mental Math: Adding and Subtracting Tens → Addition Within 100 → Repeated Addition as Multiplication → Multiplication as Equal Groups → Multiplication: Arrays → Basic Multiplication Facts (0s, 1s, 2s, 5s, 10s) → Multiplication Facts Within 100 → Division as Equal Sharing → Division as Grouping (Measurement Division) → Division: Grouping (Repeated Subtraction) Model → Division: Fair Sharing Model → Division as Equal Sharing → Division as Grouping → Basic Division Facts → Division Facts Within 100 → Multiplication and Division Fact Families → Relationship Between Multiplication and Division → Division Facts as Inverse of Multiplication → Remainders and Quotients in Division → Division Word Problems → Multi-Step Word Problems → Solving Multi-Step Word Problems → Multiplication Word Problems → Division Word Problems → Introduction to Long Division → Factors and Multiples → Prime and Composite Numbers → Equivalent Fractions → Relating Fractions and Decimals → Decimal Place Value → Integers and the Number Line → Comparing and Ordering Integers → Absolute Value → Adding Integers → Subtracting Integers → Multiplying Integers → Introduction to Exponents → Order of Operations → Integer Order of Operations → Variable Expressions → The Distributive Property → Variables and Expressions Review → Introduction to Polynomials → Adding and Subtracting Polynomials → Multiplying Polynomials → Factorial → Permutations → Combinations → Counting Principles: Addition and Multiplication Rules → Introduction to Graph Theory → Propositional Logic Foundations → Logical Equivalences → Boolean Algebra → Boolean Type and Truth Values → Comparison Operators and Boolean Tests → Logical Operators and Boolean Algebra → Conditional Statements → Defining and Calling Functions → Functions: Decomposing Problems → Function Parameters and Argument Passing → Return Values → Variable Scope → Introduction to Classes → Objects and Instances → Methods and Attributes → Algorithm Design Basics → Tree Structure and Node Properties → Binary Trees → Tree Traversals → Depth-First Search (DFS) → Depth-First Search: Implementation and Applications → Topological Sort → Dynamic Programming

Longest path: 89 steps · 468 total prerequisite topics

Prerequisites (6)

Leads To (17)