Algorithm design paradigms are recurring conceptual frameworks for constructing algorithms. A paradigm is not a specific algorithm but a general strategy—a way of thinking about how to decompose a problem, what kind of reasoning will lead to a solution, and what guarantees that solution can offer. The study of design paradigms sits at the intersection of mathematics and engineering: it asks what general patterns of problem-solving exist, when each pattern is applicable, and what trade-offs in efficiency, correctness, and simplicity each pattern entails.
The central questions of the subfield are deceptively simple. Given a computational problem, how can one structure a search for a solution? What assumptions about the input make one strategy viable and another impossible? And once a strategy is chosen, how can one prove that it terminates, that it produces the correct answer, and that it does so within acceptable resource bounds? Design paradigms provide reusable answers to these questions, turning the craft of algorithm construction into a more systematic discipline.
Before the consolidation of algorithm design as a field, algorithms were often devised ad hoc. A clever mathematician or programmer might find a solution to a specific problem, but the insight rarely transferred. The emergence of design paradigms in the mid-twentieth century was a response to this fragmentation. As computing became a scientific and industrial enterprise, researchers sought patterns that could be taught, reused, and analyzed in general terms.
The foundational insight is that many seemingly distinct problems share an underlying structure. If that structure can be identified, then a known design strategy can be applied, and the analysis of the strategy—its correctness proof and complexity bounds—can be carried over with minimal modification. This is the sense in which paradigms are "design" tools: they are templates for constructing algorithms, not finished products.
A paradigm typically specifies three things. First, a way of viewing the problem: for example, as a sequence of decisions, as a hierarchy of subproblems, or as a search over a state space. Second, a method for constructing a solution from that view: building up a solution incrementally, combining solutions to subproblems, or pruning a search tree. Third, a style of proof: the invariant that guarantees correctness, the measure that guarantees termination, or the recurrence that bounds running time.
The oldest and most intuitive paradigm is divide and conquer. The strategy is to break a problem into smaller instances of the same problem, solve those recursively, and then combine the results. The power of the approach lies in the fact that the subproblems are independent; each can be solved without reference to the others, which makes the recursion straightforward and the analysis tractable.
The classic example is merge sort. To sort a list, split it in half, sort each half recursively, and then merge the two sorted halves. The correctness follows from the fact that merging two sorted lists produces a sorted list. The running time satisfies the recurrence T(n) = 2T(n/2) + O(n), which solves to O(n log n). The same pattern appears in binary search, where the "combine" step is trivial, and in the fast Fourier transform, where the combination step is the heart of the algorithm.
The paradigm's limitation is that it requires the ability to split a problem into independent subproblems and to combine solutions efficiently. Some problems resist this decomposition because the subproblems interact. The paradigm also assumes that the recursion depth is manageable; for problems with unbalanced splits, the running time can degrade to quadratic or worse. Nevertheless, divide and conquer remains a first-line strategy because its analysis is clean and its implementations are often parallelizable.
Dynamic programming addresses problems where divide and conquer fails because subproblems overlap. In such problems, a naive recursive decomposition would solve the same subproblem many times. Dynamic programming instead computes each subproblem once, stores the result, and reuses it when needed. The paradigm is applicable when a problem exhibits optimal substructure—the optimal solution to the whole problem contains optimal solutions to its subproblems—and overlapping subproblems.
The canonical example is the Fibonacci sequence, where a recursive definition recomputes F(n-1) and F(n-2) repeatedly. A dynamic programming approach computes F(0), F(1), F(2), and so on, storing each value in a table. More substantively, the paradigm solves problems like the longest common subsequence, matrix chain multiplication, and shortest paths in graphs with nonnegative weights. In each case, the algorithm fills a table of subproblem solutions, using previously computed entries to compute new ones.
The key intellectual move in dynamic programming is the formulation of a recurrence relation that expresses the optimal solution to a problem in terms of optimal solutions to smaller subproblems. This formulation is often the hardest part; once the recurrence is written, the implementation is mechanical. The paradigm's limitation is that it requires the optimal substructure property, which does not hold for all problems. It also requires a state space small enough to store in memory; problems with high-dimensional state spaces can exhaust available storage. The approach is sometimes described as "careful brute force," because it explores all possible subproblem solutions but avoids redundant work.
Greedy algorithms take a different stance: instead of exploring all possibilities, they make a sequence of locally optimal choices, hoping that the local optimum leads to a global optimum. The paradigm is the most efficient when it works, because it typically requires only a single pass over the input and constant additional space. But it works only for problems with the greedy-choice property: a globally optimal solution can be reached by making the locally optimal choice at each step.
The classic example is the activity selection problem, where one must choose the maximum number of non-overlapping intervals. Sorting the intervals by finish time and always picking the one that finishes earliest yields an optimal solution. Similarly, Huffman coding builds an optimal prefix code by repeatedly merging the two least frequent symbols. In both cases, the proof of correctness shows that there exists an optimal solution consistent with the first greedy choice, and then applies induction.
The paradigm's danger is that it is easy to apply and hard to verify. Many problems that look like they might admit a greedy solution do not. The traveling salesman problem, for instance, is not solved by always visiting the nearest unvisited city. The distinction between problems where greed works and problems where it fails is subtle, and the paradigm is best used after proving the greedy-choice property, not before. When it does apply, however, it yields algorithms that are simple, fast, and often the most practical choice.
When a problem requires exploring a space of possibilities, and no direct formula or greedy rule is available, one can search the space systematically. Backtracking is the paradigm of incremental construction with undoing: build a solution piece by piece, and when a partial solution cannot be extended to a full solution, abandon it and try the next option. The approach is essentially a depth-first search of a decision tree, with pruning based on constraints.
The eight queens problem is the standard illustration. Place queens one by one on a chessboard; after each placement, check whether any two queens attack each other. If a placement leads to a conflict, remove the last queen and try the next square. The algorithm either finds all solutions or determines that none exist. Backtracking is complete—it will find a solution if one exists—but its running time can be exponential in the worst case.
Branch and bound is a refinement for optimization problems. Instead of merely checking feasibility, the algorithm maintains a bound on the best possible solution achievable from a partial solution. If the bound is worse than the best solution found so far, the branch is pruned. This paradigm is used for problems like the traveling salesman and integer programming, where exact solutions are needed but exhaustive search is infeasible. The quality of the bounds determines the efficiency; good bounds can make the search practical for moderately sized instances, while poor bounds leave the algorithm little better than brute force.
A different kind of paradigm does not solve a problem directly but transforms it into another problem that is easier to solve. Reduction is the general technique of showing that problem A can be converted into problem B, so that an algorithm for B yields an algorithm for A. In algorithm design, this appears as transform-and-conquer: change the representation of the input, solve the transformed problem, and then map the solution back.
The most common transformation is sorting. Many problems become easier once the input is sorted: finding duplicates, computing the median, or detecting anagrams all reduce to sorting followed by a linear scan. Another transformation is changing the data structure: representing a graph as an adjacency list versus an adjacency matrix changes which algorithms are natural. A more sophisticated example is the use of logarithms to turn multiplication into addition, or the use of modular arithmetic to simplify computations.
Reduction is also the basis of complexity theory, where it is used to show that problems are at least as hard as other problems. In that context, reductions are used negatively, to prove hardness. In algorithm design, they are used positively, to leverage existing algorithms. The paradigm's insight is that problem-solving skill consists not only of inventing new methods but also of recognizing when a new problem is really an old problem in disguise.
These paradigms are not mutually exclusive, and real algorithms often combine them. A divide-and-conquer algorithm might use dynamic programming to solve the subproblems. A greedy algorithm might be used as a heuristic within a branch-and-bound search. The boundaries between paradigms are pedagogical conveniences as much as natural divisions. What unites them is a shared concern with the structure of problems and the transferability of solution strategies.
The field has also developed meta-paradigms that sit above individual strategies. Randomized algorithms, for example, introduce randomness into the decision process, sometimes achieving better expected performance than any deterministic algorithm. Approximation algorithms relax the requirement of exactness, trading optimality for polynomial running time on NP-hard problems. Online algorithms must make decisions without seeing the entire input. These are not design paradigms in the same sense as divide and conquer, but they are general frameworks for thinking about algorithm construction under different constraints.
The durable contribution of design paradigms is not a catalogue of tricks but a way of thinking. An educated practitioner, faced with a new problem, asks: Does it decompose into independent subproblems? Does it have optimal substructure? Does it admit a greedy choice? Can it be transformed into a known problem? These questions structure the search for a solution and provide a vocabulary for discussing why one approach works and another fails. The paradigms are the grammar of algorithmic thought, and learning them is the difference between solving problems by luck and solving them by design.