Overlap is what makes memoisation pay
Merge sort's subproblems are disjoint, so caching them saves nothing. Fibonacci's recur constantly.
When subproblems overlap, recomputing them is exponentially wasteful. Storing each answer turns an exponential recursion into a polynomial one, and the technique applies exactly when the problem has optimal substructure.
Core ideas
Both conditions are needed. Optimal substructure without overlap is divide-and-conquer; overlap without optimal substructure is not helped.
Merge sort's subproblems are disjoint, so caching them saves nothing. Fibonacci's recur constantly.
The best solution must be assemblable from best sub-solutions. Longest simple path fails this, and no dynamic program for it exists.
Memoised recursion computes only the subproblems it needs; a table computes all of them in dependency order. The complexity is the same.
The material
The two conditions, three worked examples, and the problem it cannot help.
The naive recursive Fibonacci makes about 1.6ⁿ calls because it recomputes the same values exponentially often: F(5) calls F(3) twice, F(2) three times, and so on. Storing each value when first computed reduces the count to n.
Optimal substructure: an optimal solution is built from optimal solutions to subproblems. Overlapping subproblems: the recursion revisits the same subproblems many times.
Both are required. Merge sort has optimal substructure and no overlap, so it is divide-and-conquer and memoisation would help nothing. A problem with overlap and no optimal substructure cannot be solved by combining sub-solutions at all.
The recurrence is the optimal substructure written down: the best way to make v uses some coin c, and the rest must be the best way to make v − c. Filling the table costs Θ(v · |coins|), and the greedy failure of “Greedy Algorithms” disappears.
Cost Θ(mn), against exponential for the naive recursion. This is the algorithm behind diff, behind version-control merges, and behind sequence alignment in bioinformatics.
Finding the longest path with no repeated vertex has no optimal substructure: the longest path from a to c need not consist of the longest path from a to b plus the longest from b to c, because those may share vertices and the concatenation would not be simple. The problem is NP-hard, and no dynamic program for it exists.
Contrast with the SHORTEST path, which does have optimal substructure — any subpath of a shortest path is shortest — and is solved in polynomial time by Graphs and Trees's Dijkstra. Two problems whose statements differ by one word, on opposite sides of tractability.
The two have the same asymptotic cost. Bottom-up often permits dropping old rows of the table — the Fibonacci table needs only the last two entries — which is why it is preferred when memory matters.
Interactive
Counts from running, not from quoting
Method
Recurrence first; the implementation follows.
"The fewest coins making value v", "the LCS of the first i and first j characters". A vague subproblem gives no recurrence.
How an optimal solution decomposes. This is where optimal substructure is either present or absent.
The smallest subproblems, answered outright.
Same cost. Bottom-up if the space can be reduced; top-down if only some subproblems are needed.
Filling the table from 0 upward.
Every entry was computed once and read several times, which is the whole saving. The naive recursion would recompute best[3] at values 4, 6 and 7, and each of those recomputations would recurse again.
Write the recurrence for the 0/1 knapsack problem — items with weights and values, a capacity, items cannot be split. Define the subproblem in terms of the first i items and remaining capacity w, and the recurrence writes itself.
Something to change about this lesson? Write it down, tick it off when it is handled, and export the list when you want to act on it. Kept in this browser only: nothing is sent anywhere, and nobody is notified.
No recommendations yet for this lesson.