Divide-and-Conquer and Recurrences

Suppose you must sort ten million records. But Insertion Sort takes time proportional to the square of the input size. At a million operations per millisecond, that quadratic growth turns a nuisance into a catastrophe. A tenfold increase in input becomes a hundredfold increase in running time. Something structurally different is needed, not just a faster constant. Divide-and-conquer is the answer that reshaped algorithm design. Instead of solving a problem directly, you split it into smaller pieces of the same kind. You solve those recursively, then stitch the answers together. This one idea underlies fast sorting, fast multiplication, fast matrix operations, and the FFT. These technologies live inside every database, compiler, and signal processor. The paradigm turns a seemingly hard problem into a small amount of "combining" work. This work is layered on top of easier subproblems. The subtlety is that a divide-and-conquer algorithm's efficiency is not obvious from its pseudocode alone. It hides inside a recurrence relation. This is an equation describing running time in terms of running time on smaller inputs. Solving that recurrence is key. You can do this by unrolling a recursion tree or applying the Master Theorem. That is what turns "I recurse on half the array" into a hard number like O(nlog⁡n)O(n \log n). This article builds the paradigm from first principles: what divide, conquer, and combine mean precisely; how to write recurrences that model recursive algorithms; and how to solve those recurrences rigorously. It uses a recursion-tree method and the Master Theorem as a shortcut. It sets up the machinery needed to analyze Merge Sort, Quicksort, and linear-time selection algorithms that follow.

Key takeaways
  • Divide-and-conquer solves a problem by splitting it into smaller subproblems of the same type, solving each recursively, and combining the results.
  • Running time of such algorithms is captured by a recurrence relation, e.g. T(n)=aT(n/b)+f(n)T(n) = aT(n/b) + f(n).
  • The recursion tree method sums the work done at every level of recursion to find the total cost.
  • The Master Theorem gives a closed-form solution for recurrences of the form T(n)=aT(n/b)+f(n)T(n) = aT(n/b) + f(n) in three regimes.
  • Comparing f(n)f(n) against nlog⁡ban^{\log_b a} tells you whether the "combine" step or the "leaves" dominate the total cost.
  • This machinery is the analytical foundation for Merge Sort, Quicksort, and linear-time selection.
The core insight

Divide-and-conquer trades a hard problem for smaller copies of itself plus a combine step, and a recurrence relation — solved via a recursion tree or the Master Theorem — reveals whether that trade actually pays off.

The idea

A divide-and-conquer algorithm solves a problem of size nn by executing three conceptual phases. Divide splits the instance into aa subproblems, each roughly of size n/bn/b (here aa is the branching factor — how many subproblems are spawned — and bb is the shrink factor — how much smaller each subproblem is). Conquer solves each subproblem recursively, until subproblems become small enough to solve directly (the base case). Combine merges the subproblem solutions into a solution for the original instance. The paradigm is recursive by construction: the "conquer" step is just a call to the same algorithm on a smaller input. What makes divide-and-conquer powerful is not recursion alone — naive recursion can be just as slow as iteration — but the specific shape of subproblem-plus-combine that this paradigm encourages. When the combine step is cheap relative to the size of the subproblems it stitches together, the total work collapses far below what an unstructured algorithm would need. This is precisely the phenomenon that lets Merge Sort beat Insertion Sort: two sorted halves of size n/2n/2 can be merged into one sorted array of size nn in only O(n)O(n) time, so the "combine" cost grows linearly while the number of comparisons an insertion-based method needs grows quadratically. The formal tool for capturing this tradeoff is a recurrence relation: an equation expressing T(n)T(n), the running time on an input of size nn, in terms of TT evaluated at smaller arguments. The canonical shape is

T(n)=a⋅T(n/b)+f(n),T(n) = a \cdot T(n/b) + f(n),

where a≥1a \geq 1 is the number of subproblems, b>1b > 1 is the factor by which the input shrinks, and f(n)f(n) is the cost of dividing and combining (excluding the recursive calls themselves). Solving this recurrence — finding a closed-form or tight asymptotic bound for T(n)T(n) — is the analytical heart of every divide-and-conquer algorithm, and it is the subject of the rest of this article.

How it works

There are two complementary techniques for solving recurrences of the form T(n)=aT(n/b)+f(n)T(n) = aT(n/b) + f(n): unrolling the recursion into a recursion tree and summing level by level, or applying the Master Theorem, a theorem that reads off the answer directly from aa, bb, and f(n)f(n) once certain conditions are met.

The recursion-tree method. Draw the recursion as a tree: the root represents the original call, costing f(n)f(n) in non-recursive work, with aa children each representing a subproblem of size n/bn/b. Each of those children again splits into aa grandchildren of size n/b2n/b^2, and so on, until subproblems reach the base case size (typically Θ(1)\Theta(1)). Summing the non-recursive work across each level, then summing across all levels, gives the total running time. ```text procedure SOLVE(n): if n <= BASE_CASE_SIZE: return SOLVE_DIRECTLY(n) # O(1) work divide the problem into a subproblems, each of size n / b for i = 1 to a: result[i] = SOLVE(subproblem_i) # a recursive calls return COMBINE(result[1..a]) # f(n) work, excluding recursion ``` The recursion has depth log⁡bn\log_b n (the number of times you must divide nn by bb to reach the base case). At depth ii there are aia^i subproblems, each of size n/bin/b^i, so the non-recursive work at level ii is

ai⋅f ⁣(nbi).a^i \cdot f\!\left(\frac{n}{b^i}\right).

Summing over all levels i=0,1,…,log⁡bni = 0, 1, \dots, \log_b n gives the total cost, plus the cost of the leaves (there are alog⁡bn=nlog⁡baa^{\log_b n} = n^{\log_b a} leaves, each doing Θ(1)\Theta(1) work). This method works for any f(n)f(n), even ones the Master Theorem cannot handle, but it requires you to recognize and sum a series — sometimes a geometric series, sometimes an arithmetic one, depending on how f(n)f(n) compares across levels.

The Master Theorem. For recurrences of the exact form T(n)=aT(n/b)+f(n)T(n) = aT(n/b) + f(n) with a≥1a \geq 1, b>1b > 1, compare f(n)f(n) to the watershed function nlog⁡ban^{\log_b a} (this is exactly the number of leaves in the recursion tree, i.e. the cost if all work happened only at the base cases): ```text MASTER THEOREM: given T(n) = a·T(n/b) + f(n), let n_crit = n^(log_b a) Case 1 (leaves dominate): if f(n) = O(n_crit / n^ε) for some constant ε > 0, then T(n) = Θ(n_crit) Case 2 (balanced — every level contributes equally): if f(n) = Θ(n_crit · log^k n) for some k >= 0, then T(n) = Θ(n_crit · log^(k+1) n) Case 3 (root/combine step dominates): if f(n) = Ω(n_crit · n^ε) for some constant ε > 0, AND the regularity condition a·f(n/b) <= c·f(n) holds for some constant c < 1 and all sufficiently large n, then T(n) = Θ(f(n)) ``` Intuitively: Case 1 says the tree's leaves (the many tiny base-case subproblems) dominate the total work, so the answer is the leaf count. Case 2 says every level of the tree contributes about the same amount of work, so you multiply the per-level cost by the number of levels (log⁡n\log n), possibly gaining an extra logarithmic factor. Case 3 says the root's combine step is so expensive that it dominates everything below it, so the answer is just f(n)f(n) itself — provided the regularity condition rules out pathological cases where f(n)f(n) oscillates. Not every recurrence falls into one of these three cases (there can be gaps, e.g. f(n)=nlog⁡ba/log⁡nf(n) = n^{\log_b a}/\log n satisfies none of them), in which case the recursion-tree method or more advanced tools (the Akra–Bazzi method) are needed.

Figure
Recursion tree for T(n) = 2T(n/2) + n, unrolled to the base case
n cost = n n/2 n/2 cost = n/2 + n/2 = n n/4 n/4 n/4 n/4 = n ⋮ (log₂n levels total, each costing n) n leaves, each Θ(1) work → Θ(n) total at the base Total: (log₂n levels) × (n per level) = Θ(n log n) Matches Master Theorem Case 2: f(n) = n = Θ(n^(log₂2)·log⁰n) ⇒ T(n) = Θ(n log n)

Complexity & correctness

Correctness of the recursion-tree summation. The recursion tree is not a heuristic drawing; it is a faithful unrolling of the recurrence, and this can be proven by induction on the recursion depth. At depth ii, there are exactly aia^i nodes (since each node spawns aa children — this is the definition of the divide step), and each corresponds to a subproblem of size n/bin/b^i (since the size shrinks by a factor bb at each level — again, by definition). The non-recursive work performed by each such node is f(n/bi)f(n/b^i), so the total work at level ii is aif(n/bi)a^i f(n/b^i), and summing over levels i=0i = 0 to log⁡bn−1\log_b n - 1 plus the leaf-level cost gives T(n)T(n) exactly, by the recurrence's own definition applied repeatedly. There is no approximation in the tree itself — only in how one bounds the resulting sum asymptotically.

Correctness of the Master Theorem. The three cases correspond to which term of the sum

T(n)=Θ(nlog⁡ba)+∑i=0log⁡bn−1aif(n/bi)T(n) = \Theta(n^{\log_b a}) + \sum_{i=0}^{\log_b n - 1} a^i f(n/b^i)

dominates asymptotically. Case 1 occurs when ff grows polynomially slower than nlog⁡ban^{\log_b a}: then the sum is dominated by its last few terms (close to the leaves), which are geometrically comparable to nlog⁡ban^{\log_b a}, so the leaf term wins. Case 3 occurs when ff grows polynomially faster: then the sum is dominated by its first term (the root), and the regularity condition ensures the recursive subproblems don't conspire to exceed a constant fraction of f(n)f(n), so f(n)f(n) itself is the answer. Case 2 is the boundary: f(n)=Θ(nlog⁡balog⁡kn)f(n) = \Theta(n^{\log_b a} \log^k n) makes every term in the sum comparable, so there are Θ(log⁡n)\Theta(\log n) nearly-equal terms, each Θ(nlog⁡balog⁡kn)\Theta(n^{\log_b a} \log^k n), giving a total of Θ(nlog⁡balog⁡k+1n)\Theta(n^{\log_b a} \log^{k+1} n). A full proof (as in CLRS) makes this rigorous with the geometric-series and floor/ceiling technicalities, but the intuition above is exactly why the three cases exist and why they partition the space of "reasonable" f(n)f(n).

Time complexity of common recurrences, derived from the theorem:

Recurrenceaa, bb, f(n)f(n)nlog⁡ban^{\log_b a}CaseResult
T(n)=2T(n/2)+nT(n) = 2T(n/2) + na=2,b=2,f=na=2,b=2,f=nn1=nn^{1}=n2, k=0k=0Θ(nlog⁡n)\Theta(n \log n)
T(n)=2T(n/2)+1T(n) = 2T(n/2) + 1a=2,b=2,f=1a=2,b=2,f=1n1=nn^1 = n1Θ(n)\Theta(n)
T(n)=T(n/2)+1T(n) = T(n/2) + 1a=1,b=2,f=1a=1,b=2,f=1n0=1n^0=12, k=0k=0Θ(log⁡n)\Theta(\log n)
T(n)=4T(n/2)+nT(n) = 4T(n/2) + na=4,b=2,f=na=4,b=2,f=nn2n^21Θ(n2)\Theta(n^2)
T(n)=T(n/2)+nT(n) = T(n/2) + na=1,b=2,f=na=1,b=2,f=nn0=1n^0=13Θ(n)\Theta(n)
T(n)=7T(n/2)+n2T(n) = 7T(n/2) + n^2a=7,b=2,f=n2a=7,b=2,f=n^2nlog⁡27≈n2.81n^{\log_2 7} \approx n^{2.81}1Θ(n2.81)\Theta(n^{2.81}) (Strassen's matrix multiplication)

Space complexity. Divide-and-conquer recursion consumes stack space proportional to the recursion depth times the space per frame; for a balanced split (b>1b>1), depth is Θ(log⁡n)\Theta(\log n), so auxiliary stack space is typically O(log⁡n)O(\log n) beyond whatever space the combine step itself allocates (e.g. Merge Sort's merge buffers add O(n)O(n) separately).

Honest tradeoffs. The Master Theorem only applies to the specific syntactic form aT(n/b)+f(n)aT(n/b)+f(n) with constant a,ba,b; recurrences with unequal-sized subproblems (like T(n)=T(n/3)+T(2n/3)+nT(n) = T(n/3) + T(2n/3) + n, which arises in some Quicksort analyses) require the recursion-tree method or the more general Akra–Bazzi theorem instead. The regularity condition in Case 3 is easy to overlook and is genuinely necessary — without it, wildly oscillating f(n)f(n) can break the conclusion.

Worked example

Trace T(n)=2T(n/2)+nT(n) = 2T(n/2) + n — the recurrence for Merge Sort — using the recursion tree explicitly for n=16n = 16, then confirm with the Master Theorem.

Level ii# subproblems (2i2^i)Size of each (16/2i16/2^i)Non-recursive cost per nodeTotal cost at level
01161616
128816
244416
382216
4 (base)161116

There are log⁡216=4\log_2 16 = 4 non-base levels plus one base level, i.e. 5 levels total, each costing exactly 1616. Summing: 5×16=805 \times 16 = 80. In general, for input size nn, there are log⁡2n+1\log_2 n + 1 levels each costing nn, giving T(n)=n(log⁡2n+1)=Θ(nlog⁡n)T(n) = n(\log_2 n + 1) = \Theta(n \log n) — matching n=16n=16: 16×5=80=16(log⁡216+1)=16×516 \times 5 = 80 = 16(\log_2 16 + 1) = 16 \times 5. ✓. Now confirm with the Master Theorem: a=2a = 2, b=2b = 2, f(n)=nf(n) = n. The watershed function is nlog⁡ba=nlog⁡22=n1=nn^{\log_b a} = n^{\log_2 2} = n^1 = n. Since f(n)=n=Θ(n1log⁡0n)f(n) = n = \Theta(n^1 \log^0 n), this is Case 2 with k=0k = 0, giving T(n)=Θ(n1log⁡0+1n)=Θ(nlog⁡n)T(n) = \Theta(n^1 \log^{0+1} n) = \Theta(n \log n) — exactly matching the tree summation. This is the recurrence that governs Merge Sort's running time, and it's why Merge Sort at n=10,000,000n = 10{,}000{,}000 needs on the order of nlog⁡2n≈2.3×108n \log_2 n \approx 2.3 \times 10^8 operations, versus Insertion Sort's n2=1014n^2 = 10^{14} — a gap of six orders of magnitude that makes the divide-and-conquer approach not just theoretically nicer but practically indispensable. As a contrasting second case, consider T(n)=3T(n/2)+nT(n) = 3T(n/2) + n (a recurrence resembling some multiplication algorithms). Here a=3a=3, b=2b=2, so nlog⁡23≈n1.585n^{\log_2 3} \approx n^{1.585}. Since f(n)=nf(n) = n grows polynomially slower than n1.585n^{1.585} (take ϵ=0.5\epsilon = 0.5: n=O(n1.585−0.5)=O(n1.085)n = O(n^{1.585 - 0.5}) = O(n^{1.085}), true), this is Case 1, giving T(n)=Θ(n1.585)T(n) = \Theta(n^{1.585}) — the leaves dominate, not the linear combine step, illustrating how a small change in branching factor aa shifts which case applies.

Common pitfalls & traps

PitfallWhy it happensFix
Forgetting the base case in the recurrence or pseudocodeInfinite recursion / stack overflow on small inputsAlways specify T(1)=Θ(1)T(1) = \Theta(1) or similar, and code an explicit base-case check
Misidentifying aa or bbConfusing "number of subproblems" with "size reduction factor"Rewrite the algorithm's recursive calls explicitly before assigning a,ba, b
Applying the Master Theorem when the case conditions aren't strictly metf(n)f(n) must be polynomially larger/smaller, not just asymptotically larger/smaller, for Cases 1/3Check the polynomial-gap condition with an explicit ϵ\epsilon; if none exists, fall back to the recursion tree
Skipping the regularity condition in Case 3It looks like a technicality, but ensures the algorithm doesn't recurse in a self-defeating wayVerify af(n/b)≤cf(n)a f(n/b) \le c f(n) for constant c<1c<1, or use Akra–Bazzi
Treating unequal-size subproblems as if the Master Theorem appliesMaster Theorem assumes all aa subproblems have the same size n/bn/bUse a recursion tree or Akra–Bazzi for recurrences like T(n)=T(n/3)+T(2n/3)+nT(n)=T(n/3)+T(2n/3)+n
Ignoring floors/ceilings (n/bn/b vs ⌊n/b⌋\lfloor n/b \rfloor)Real inputs aren't always divisible by bbFine for asymptotic (Θ\Theta) analysis by the theorem's floor/ceiling extension, but matters for exact counts

Pioneers & history

The divide-and-conquer paradigm predates modern computing — Carl Friedrich Gauss used a divide-and-conquer trick for complex multiplication in the 1800s — but its formalization as a general algorithmic strategy, together with the recurrence-based analysis that quantifies its efficiency, crystallized during the growth of theoretical computer science in the mid-20th century. John von Neumann's 1945 description of Merge Sort is often cited as one of the first explicit uses of the paradigm on a stored-program computer, merging sorted runs recursively. The systematic study of recurrence relations for algorithm analysis, and the Master Theorem itself, developed through the work of algorithm analysts including Jon Bentley, Dorothea Haken, and James B. Saxe, who published a general method (the "Bentley–Haken–Saxe theorem," the ancestor of the modern Master Theorem) in 1980.

Origins · 1 minJohn von Neumann and how this was discovered
JV
John von Neumann
1903–1957 · Pioneer of the stored-program computer and of merge-based sorting

Von Neumann's 1945 report on the EDVAC design included one of the earliest known descriptions of an algorithm recognizable as Merge Sort, applying a divide-and-conquer strategy to sort data too large to fit conveniently for direct comparison sorts, decades before the asymptotic machinery to formally justify its efficiency existed.

History
1945
— von Neumann describes an early merge-sort procedure for the EDVAC.
1962
— Tony Hoare publishes Quicksort, a divide-and-conquer algorithm partitioning in place.
1971
— Volker Strassen publishes an O(nlog⁡27)O(n^{\log_2 7}) divide-and-conquer matrix multiplication algorithm, beating the naive O(n3)O(n^3).
1980
— Bentley, Haken, and Saxe formalize a general theorem for solving divide-and-conquer recurrences, ancestor of the Master Theorem.
1990
— Cormen, Leiserson, and Rivest's Introduction to Algorithms popularizes the Master Theorem in its now-standard three-case form.

Where this matters

Divide-and-conquer recurrence analysis is the analytical backbone behind nearly every efficient comparison-based sort and search structure used in production systems. Database engines and standard-library sort routines rely on Merge Sort and Quicksort variants whose Θ(nlog⁡n)\Theta(n \log n) guarantees come directly from Master Theorem Case 2 reasoning; selection algorithms used in statistics libraries and median-finding (leading into linear-time selection) depend on recurrences solved by the same recursion-tree technique, sometimes falling into Case 1 for a linear Θ(n)\Theta(n) result. Beyond sorting, the Fast Fourier Transform — essential to audio/video codecs, wireless signal processing, and scientific computing — is a divide-and-conquer algorithm whose Θ(nlog⁡n)\Theta(n \log n) running time is a textbook Case 2 application. Strassen's divide-and-conquer matrix multiplication, and its descendants, underlie some numerical linear algebra libraries used in large-scale machine learning and scientific simulation. Compilers and interpreters use divide-and-conquer parsing strategies whose complexity is likewise governed by recurrence analysis, and distributed systems apply the same "split, solve independently, merge" pattern at the level of MapReduce-style computations across machines rather than array indices.

Ask the tutor: How would the recurrence and Master Theorem case change if Quicksort always picked the worst possible pivot?

What exactly distinguishes divide-and-conquer from plain recursion?

Plain recursion just means a function calls itself; divide-and-conquer additionally requires that the problem be split into independent subproblems of the same type, solved separately, and then explicitly combined. A recursive Fibonacci function, for instance, is recursive but not really divide-and-conquer in the useful sense, because its "subproblems" overlap heavily and there's no combine step doing structural work — it's closer to naive recursion with redundant computation. True divide-and-conquer algorithms like Merge Sort have a combine phase (the merge) that does real, non-trivial work, and that combine cost is exactly the f(n)f(n) term whose growth rate determines the whole algorithm's efficiency via the Master Theorem.

Can the Master Theorem handle recurrences with subtraction, like T(n) = T(n-1) + n?

No — the Master Theorem is specifically for recurrences where the subproblem size shrinks by a constant factor (division by bb), not a constant amount (subtraction). T(n)=T(n−1)+nT(n) = T(n-1) + n describes linear recursion depth (nn levels, not log⁡n\log n), giving T(n)=Θ(n2)T(n) = \Theta(n^2) by direct summation (it's an arithmetic series n+(n−1)+⋯+1n + (n-1) + \cdots + 1), but this falls entirely outside the Master Theorem's scope. Recurrences like this are typically solved by direct summation or the substitution method (guess a form, verify by induction) rather than the recursion tree or Master Theorem, both of which assume multiplicative shrinkage.

What is the "regularity condition" in Case 3, intuitively?

It rules out situations where f(n)f(n) grows fast overall but shrinks unpredictably when you plug in n/bn/b, in a way that could let the recursive terms sneak past f(n)f(n)'s dominance. Concretely, af(n/b)≤cf(n)a f(n/b) \le c f(n) for some constant c<1c<1 says: the total work contributed by expanding one more level of recursion is at most a constant fraction of the current level's cost. Most "nice" functions — polynomials, polynomials times logarithms — satisfy this automatically. It becomes relevant mainly for pathological or rapidly oscillating f(n)f(n), which rarely arise from real algorithms but do arise in constructed counterexamples used to teach why the condition is necessary.

Why does Case 2's answer include an extra log factor beyond n^(log_b a)?

Because Case 2 describes the situation where every level of the recursion tree contributes comparable work, not just the leaves or just the root. If there are Θ(log⁡n)\Theta(\log n) levels and each contributes Θ(nlog⁡ba)\Theta(n^{\log_b a}) work (the k=0k=0 sub-case), the total is the per-level cost multiplied by the number of levels, i.e., Θ(nlog⁡balog⁡n)\Theta(n^{\log_b a} \log n) — one extra factor of log⁡n\log n compared to the leaf-only count nlog⁡ban^{\log_b a}. The general k>0k>0 version follows the same logic with log⁡kn\log^k n folded into the per-level cost, giving log⁡k+1n\log^{k+1} n overall.

How does the recursion-tree method handle recurrences the Master Theorem can't, like T(n) = 2T(n/2) + n log n?

Here f(n)=nlog⁡nf(n) = n \log n doesn't fit any Master Theorem case cleanly (it's not a polynomial gap above or below nlog⁡22=nn^{\log_2 2}=n, since log⁡n\log n is not polynomial growth) — this is exactly the kind of gap the theorem leaves open. The recursion tree resolves it directly: at level ii, there are 2i2^i subproblems of size n/2in/2^i, contributing 2i⋅(n/2i)log⁡(n/2i)=n(log⁡n−i)2^i \cdot (n/2^i)\log(n/2^i) = n(\log n - i) work. Summing i=0i=0 to log⁡n−1\log n - 1 gives n∑i=0log⁡n−1(log⁡n−i)=n⋅Θ(log⁡2n)n \sum_{i=0}^{\log n -1}(\log n - i) = n \cdot \Theta(\log^2 n), so T(n)=Θ(nlog⁡2n)T(n) = \Theta(n \log^2 n) — a result the Master Theorem's stated cases cannot directly produce, though it is sometimes handled by an extended version of Case 2.

Does a smaller branching factor a always mean a faster algorithm?

Not necessarily — it depends on how aa trades off against f(n)f(n). Reducing aa (fewer subproblems) shrinks the leaf count nlog⁡ban^{\log_b a}, which helps if leaves dominate (Case 1), but if the combine step already dominates (Case 3), reducing aa doesn't change the asymptotic running time at all, since T(n)=Θ(f(n))T(n)=\Theta(f(n)) regardless of aa in that regime. This is precisely why some algorithms (like Strassen's matrix multiplication, which reduces aa from 8 to 7 at the cost of a more complex combine step) are worthwhile: the reduction in aa shifts the watershed exponent log⁡ba\log_b a down enough to beat the naive algorithm even though f(n)f(n) stays polynomial.

Why do we assume subproblems are independent in divide-and-conquer? What if they're not?

Independence is what makes "solve each subproblem separately" valid — if subproblems shared state or depended on each other's answers, recursive calls couldn't simply be summed as aa parallel copies of T(n/b)T(n/b), and the whole recurrence-based analysis would break down. When subproblems do overlap (as in naive recursive Fibonacci, or in some dynamic-programming-shaped problems), the fix is not divide-and-conquer's recurrence machinery but memoization or bottom-up dynamic programming, which explicitly caches shared subproblem results rather than recomputing them — a genuinely different technique from the independent-subproblem model this article analyzes.

Before this

Where this leads