{"post":{"slug":"dynamic-programming-explained-2026","title":"Dynamic programming explained in 2026: memoisation, tabulation, and patterns","excerpt":"Dynamic programming turns exponential brute-force into polynomial solutions by reusing overlapping subproblems. Here are the patterns you need in 2026.","category":"code","date":"March 10, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">D</span>ynamic programming sounds intimidating but the core idea is simple: if you solve the same subproblem more than once, cache the answer and reuse it. That one principle transforms the naive exponential Fibonacci into a linear computation, and the brute-force 0-1 knapsack into a polynomial algorithm. The challenge is recognising when DP applies and designing the state correctly.\n\n## What changed in 2026\n\n- **LLMs explain DP but still struggle to design state.** AI assistants can reproduce textbook DP solutions but often produce incorrect recurrences on novel problems. Understanding state design is still a human skill.\n- **DP is common in competitive AI inference.** KV-cache in transformer inference is a form of memoisation — caching attention computations across tokens. The concept is everywhere.\n- **Interview expectations shifted.** Exhaustive DP drilling declined at some companies, but recognising DP applicability and articulating the recurrence clearly remains a strong signal.\n- **`functools.cache` is now preferred over `lru_cache(maxsize=None)` in Python 3.9+.** It is faster, has better type inference, and communicates intent clearly.\n\n## Two necessary conditions for DP\n\n**1. Optimal substructure:** The optimal solution to the problem is composed of optimal solutions to its subproblems.\n- Shortest path: optimal path from A to C via B = optimal A→B + optimal B→C. ✓\n- Longest path (no weights): not optimal substructure; DP does not apply. ✗\n\n**2. Overlapping subproblems:** The same subproblems appear repeatedly in the recursion tree.\n- Fibonacci: `fib(5)` calls `fib(4)` and `fib(3)`; `fib(4)` also calls `fib(3)`. ✓\n- Binary search: each subproblem is independent (different half of array). ✗ — use divide and conquer, not DP.\n\n## Top-down vs bottom-up\n\n| Aspect | Top-down (memoisation) | Bottom-up (tabulation) |\n|---|---|---|\n| Code style | Recursive + cache | Iterative + table |\n| Ease of writing | Easier — start from the recursive solution | Harder — must determine fill order |\n| Overhead | Call-stack frames, dict/map lookups | None — direct array access |\n| Stack overflow risk | Yes for deep recursion | No |\n| Space optimisation | Harder | Easy — can often use rolling arrays |\n\n### Top-down example: Fibonacci\n\n```python\nfrom functools import cache\n\n@cache\ndef fib(n: int) -> int:\n    if n <= 1:\n        return n\n    return fib(n - 1) + fib(n - 2)\n```\n\n### Bottom-up example: Fibonacci\n\n```python\ndef fib(n: int) -> int:\n    if n <= 1:\n        return n\n    prev, curr = 0, 1\n    for _ in range(2, n + 1):\n        prev, curr = curr, prev + curr\n    return curr\n```\n\nThe bottom-up version uses O(1) space instead of O(n). Recognising when you only need the last k rows/values is one of the most common DP optimisations.\n\n## The six core DP patterns\n\n| Pattern | Canonical problem | State dimensions |\n|---|---|---|\n| 1D linear | Climbing stairs, house robber | dp[i] |\n| 2D grid | Unique paths, minimum path sum | dp[i][j] |\n| Knapsack | 0-1 knapsack, coin change | dp[i][w] |\n| LCS/LIS | Longest common subsequence | dp[i][j] |\n| Interval | Matrix chain multiplication | dp[i][j] |\n| Tree DP | Diameter of binary tree | dp[node] |\n\n### Knapsack example (coin change)\n\n```python\ndef coin_change(coins: list[int], amount: int) -> int:\n    dp = [float('inf')] * (amount + 1)\n    dp[0] = 0                        # base case: 0 coins for amount 0\n    for a in range(1, amount + 1):\n        for c in coins:\n            if c <= a:\n                dp[a] = min(dp[a], dp[a - c] + 1)\n    return dp[amount] if dp[amount] != float('inf') else -1\n```\n\nState: `dp[a]` = minimum coins to make amount `a`. Recurrence: `dp[a] = min(dp[a - c] + 1)` for each coin `c ≤ a`.\n\n## State design process\n\n1. **Define what the state represents.** `dp[i]` = answer for the first `i` elements.\n2. **Write the recurrence.** How does `dp[i]` depend on earlier states?\n3. **Identify base cases.** What are the trivially known values (empty input, zero amount)?\n4. **Choose fill order.** Bottom-up must fill states in an order where dependencies are already computed.\n5. **Optimise space if needed.** If `dp[i]` only depends on `dp[i-1]`, keep only two variables.\n\n## Time and space complexity\n\n| Problem | Time | Space | Optimised space |\n|---|---|---|---|\n| Fibonacci | O(n) | O(n) top-down | O(1) bottom-up |\n| Longest common subseq. | O(nm) | O(nm) | O(min(n,m)) rolling |\n| 0-1 knapsack | O(nW) | O(nW) | O(W) 1D array |\n| Edit distance | O(nm) | O(nm) | O(min(n,m)) |\n\n## How to pick\n\n1. **Does the problem ask for an optimum (min/max) or count?** → Strong DP signal.\n2. **Can you define a recursive solution with overlapping subproblems?** → Add memoisation.\n3. **Is n ≤ ~10 000 and W ≤ ~10 000?** → O(nW) DP fits in memory and time.\n4. **Are subproblems independent?** → Divide and conquer (merge sort, quick sort) — not DP.\n5. **Does the recursion blow the stack?** → Convert to bottom-up tabulation.\n\n## Common mistakes\n\n**Incorrect recurrence direction.** For a knapsack variant, iterating the capacity forward vs backward can flip the problem from unbounded to 0-1 knapsack. Know which variant you need.\n\n**Off-by-one in state indexing.** Defining `dp[i]` as \"the first i elements\" vs \"ending at index i\" produces different recurrences and different base cases. Commit to one definition clearly.\n\n**Forgetting the base case.** Missing `dp[0] = 0` or `dp[0][0] = 1` causes the whole table to propagate the wrong initial value.\n\n**Not clearing the cache between test cases.** If using `@cache` in a competitive-programming context with multiple test cases, call `fib.cache_clear()` between runs.\n\n## What to skip\n\n- **DP for greedy-solvable problems.** Interval scheduling, activity selection, and fractional knapsack have greedy O(n log n) solutions; DP is heavier than necessary.\n- **2D DP when a 1D rolling array suffices.** If `dp[i][j]` only depends on `dp[i-1][*]`, store only the current and previous rows.\n- **Memoising with mutable arguments.** `@cache` on a function that takes a list fails; convert to tuples. See [Recursion explained in 2026](/blog/recursion-explained-2026) for related memoisation patterns.\n\n## FAQ\n\n**What is the difference between DP and greedy?**\nBoth solve optimisation problems, but greedy makes a locally optimal choice at each step without reconsidering. DP explores all choices via subproblems. Greedy is faster but only correct for certain problem structures.\n\n**Is DP only for 1D and 2D problems?**\nNo. DP state can have any number of dimensions. TSP (travelling salesman) uses a bitmask DP with O(n² 2^n) complexity. Practicality is the constraint, not structure.\n\n**How do I know if my recurrence is correct?**\nStart with a tiny example (n = 3), trace the table by hand, and verify it matches the brute-force answer. Then test on edge cases (empty input, single element, all same values).\n\n**Can LLMs solve DP problems reliably?**\nThey reproduce known patterns (Fibonacci, knapsack, LCS) accurately. On novel problem descriptions or unusual constraints they often produce plausible but wrong recurrences. Always verify the logic.\n\n## Where to go next\n\n- [Recursion explained in 2026](/blog/recursion-explained-2026)\n- [Big-O notation explained in 2026](/blog/big-o-notation-explained-2026)\n- [Binary search explained in 2026](/blog/binary-search-explained-2026)","hue":315,"metaTitle":"Dynamic Programming Explained 2026: Patterns and Trade-offs","metaDescription":"Practical 2026 guide to dynamic programming: memoisation vs tabulation, state design, the six core patterns, and when DP is and is not the right tool.","keywords":["dynamic programming explained 2026","memoisation vs tabulation","dp state design","dynamic programming patterns 2026","overlapping subproblems","optimal substructure","knapsack problem dp","longest common subsequence dp","bottom up vs top down dp","dynamic programming interview 2026"],"tldr":["**DP requires two properties** — optimal substructure (the optimal solution contains optimal subsolutions) and overlapping subproblems (subproblems repeat).","**Top-down (memoisation) is easier to write** — start with the recursive solution and cache results; bottom-up (tabulation) is usually faster due to no call overhead.","**State design is the hard part** — get the state definition wrong and the table grows exponentially or the recurrence is incorrect.","**Most DP problems fall into six patterns** — 1D linear, 2D grid, knapsack, LCS/LIS, interval, and tree DP.","**Skip:** applying DP to a problem without overlapping subproblems — if subproblems are independent (like merge sort), DP adds cache overhead for no benefit."],"readTime":"5 min read","wordCount":1171},"related":[{"slug":"what-is-dynamic-programming-2026","title":"What Is Dynamic Programming? A 2026 Beginner Guide","excerpt":"Dynamic programming caches subproblem answers instead of recomputing them. This 2026 beginner guide walks through the two-question test and a full worked example from first principles.","category":"code","date":"July 22, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":280},{"slug":"design-patterns-singleton-explained-2026","title":"The Singleton Pattern Explained in 2026","excerpt":"Singleton guarantees exactly one instance of a class exists and gives it a global access point. Here is what it is good for in 2026, and why many teams now avoid it by default.","category":"code","date":"July 1, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":320},{"slug":"memoization-explained-2026","title":"Memoization explained in 2026: caching results the right way","excerpt":"Memoization trades memory for speed by caching a function output keyed on its inputs. Here is the 2026 guide to how it works, when it helps, and the cache-invalidation traps that bite people.","category":"code","date":"June 29, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":290}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"dns-explained-2026","title":"DNS explained in 2026: how domain name resolution actually works","excerpt":"DNS is the phonebook of the internet — but in 2026 it also handles service discovery, failover, and encrypted queries. Here is the full picture.","category":"code","date":"March 10, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":310},"older":{"slug":"environment-variables-explained-2026","title":"Environment variables explained in 2026: config done right","excerpt":"Environment variables are the standard way to configure software across environments, but most teams manage them poorly. Here is the 2026 guide to doing it right.","category":"code","date":"March 10, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":308}}