15.23 Design Patterns
After studying many divide-and-conquer algorithms, they can appear unrelated.
15.23 Design Patterns
Problem
After studying many divide-and-conquer algorithms, they can appear unrelated.
Consider:
- Merge sort
- Quick sort
- Quickselect
- FFT
- Closest pair of points
- Karatsuba multiplication
- Strassen multiplication
- Binary search
- Inversion counting
- Offline query processing
The details differ dramatically.
Some work on arrays.
Some work on geometry.
Some work on algebra.
Some work on answer spaces rather than data.
How do experienced algorithm designers recognize when divide and conquer is the right approach?
Solution
Learn the recurring design patterns.
Most divide-and-conquer algorithms belong to a small number of structural families.
Instead of memorizing individual algorithms, learn the patterns that generate them.
When a new problem appears, ask:
Which divide-and-conquer pattern fits?
The answer often suggests the algorithm.
Pattern 1: Split and Merge
The most recognizable pattern.
Structure:
split input
solve left
solve right
merge results
Examples:
- Merge sort
- Inversion counting
- External merge sort
- Merge-sort tree construction
The combine step assembles a complete answer from complete subanswers.
Visual structure:
input
/ \\n left right
\ /
merge
This is the classic divide-and-conquer template.
Pattern 2: Split and Select
Instead of solving both halves, solve only one.
Structure:
split
determine which side
contains answer
recurse into one side
Examples:
- Binary search
- Quickselect
- Median of medians
- Many search algorithms
Visual structure:
input
/ \\n left right
X
\\n recurse
This pattern often produces:
$$ O(\log n) $$
or:
$$ O(n) $$
solutions because half the search space is discarded.
Pattern 3: Split and Partition
The goal is not merging.
The goal is reorganizing data.
Structure:
choose pivot
partition
recurse independently
Examples:
- Quick sort
- Three-way quick sort
- Introselect
- Some geometric algorithms
Visual structure:
input
|
partition
/ \\n left right
The partition operation becomes the central primitive.
Pattern 4: Even-Odd Decomposition
Separate a problem into alternating components.
Structure:
even part
odd part
solve recursively
combine algebraically
Examples:
- FFT
- Polynomial evaluation
- Signal transforms
Example:
$$ P(x) = P_{even}(x^2) + xP_{odd}(x^2) $$
The decomposition is mathematical rather than geometric.
The recursive structure remains the same.
Pattern 5: Geometric Divide and Conquer
Split space rather than sequence positions.
Structure:
split by coordinate
solve subregions
handle crossing cases
Examples:
- Closest pair of points
- Convex hull algorithms
- Range searching
- Spatial indexing
Visual structure:
plane
|
vertical split
/ \\nL R
The challenge is usually proving that crossing cases can be handled efficiently.
Pattern 6: Answer Space Division
Divide possible answers instead of input data.
Structure:
candidate answers
split candidate range
test midpoint
discard half
Examples:
- Binary search
- Binary search on answer
- Parametric search
- Numerical root finding
Visual structure:
possible answers
1 ... mid ... n
The input never changes.
Only the search interval changes.
This is still divide and conquer.
Pattern 7: Value Space Division
Divide values rather than positions.
Structure:
small values
large values
route work recursively
Examples:
- Parallel binary search
- Offline k-th order statistics
- Wavelet trees
- Some database query algorithms
Visual structure:
values
<= mid
> mid
This is common in advanced offline processing.
Pattern 8: Time Division
Split time intervals recursively.
Structure:
time range
left interval
right interval
Examples:
- Offline dynamic connectivity
- Segment tree over time
- Rollback algorithms
- Event processing systems
Visual structure:
time
[-----]
/ \\nL R
The recursive tree represents intervals rather than objects.
Pattern 9: Matrix Block Decomposition
Split matrices into quadrants.
Structure:
$$ A= \begin{bmatrix} A_{11} & A_{12}\\nA_{21} & A_{22} \end{bmatrix} $$
Solve recursively on blocks.
Examples:
- Strassen multiplication
- Cache-oblivious transpose
- Recursive matrix multiplication
- Scientific computing kernels
Visual structure:
+----+----+
| A11| A12|
+----+----+
| A21| A22|
+----+----+
The recursive unit is a matrix block.
Pattern 10: Tree Decomposition
Trees naturally decompose into subtrees.
Structure:
node
left subtree
right subtree
Examples:
- Tree DP
- Lowest common ancestor preprocessing
- Heavy-light decomposition components
- Expression evaluation
Visual structure:
root
/ \\n left right
Many tree algorithms are divide and conquer in disguise.
Pattern 11: Recursive Reduction
Shrink the problem aggressively.
Structure:
reduce size
solve smaller problem
reconstruct answer
Examples:
- Karatsuba multiplication
- Exponentiation by squaring
- Recursive numerical algorithms
The divide step may not create multiple subproblems.
The key idea is dramatic reduction.
Pattern 12: Hierarchical Aggregation
Build answers at multiple scales.
Structure:
small answers
combine
larger answers
combine
larger answers
Examples:
- Segment trees
- Sparse tables
- Merge-sort trees
- Fenwick-like recursive structures
The algorithm constructs information layer by layer.
Recognizing Divide-and-Conquer Opportunities
Experienced designers often look for specific clues.
Clue 1: Natural Halves
Example:
array midpoint
tree children
matrix quadrants
Natural halves often suggest recursive decomposition.
Clue 2: Independent Subproblems
If two parts can be solved without interacting:
left side
right side
divide and conquer becomes attractive.
Clue 3: Fast Combine Step
The recurrence:
$$ T(n)=2T(n/2)+O(n) $$
works well.
The recurrence:
$$ T(n)=2T(n/2)+O(n^2) $$
often does not.
A cheap combine step is valuable.
Clue 4: Monotonic Search Space
If feasible answers look like:
false false false true true true
binary search may apply.
Clue 5: Recursive Symmetry
If a structure repeats at smaller scales:
fractal
tree
signal
matrix
recursive decomposition is often natural.
When Divide and Conquer Is a Bad Fit
Not every problem benefits.
Warning signs:
Heavy Interaction Between Subproblems
If every subproblem depends heavily on every other subproblem:
left constantly needs right
right constantly needs left
combining may become expensive.
Expensive Merge
If combine costs:
$$ O(n^2) $$
the recurrence may not improve anything.
Tiny Inputs
Recursive overhead may dominate.
Iterative solutions are often better.
Streaming Data
Divide and conquer usually assumes the full input is available.
Streaming systems often favor incremental algorithms.
Dynamic Updates
Frequent mutations may invalidate recursive preprocessing.
Online structures may be preferable.
Pattern Selection Guide
| Problem Characteristic | Common Pattern |
|---|---|
| Sorting | Split and merge |
| Selection | Split and select |
| Searching | Answer-space division |
| Geometry | Geometric decomposition |
| Polynomial operations | Even-odd decomposition |
| Matrix operations | Block decomposition |
| Offline queries | Time/value division |
| Trees | Tree decomposition |
| Numerical approximation | Answer-space division |
| Cache optimization | Recursive blocking |
This table is often more useful than memorizing individual algorithms.
Combining Patterns
Advanced algorithms frequently combine multiple patterns.
Examples:
Closest Pair
Uses:
geometric division
+
merge-style combine
FFT
Uses:
even-odd decomposition
+
hierarchical aggregation
Parallel Merge Sort
Uses:
split and merge
+
parallel recursion
Segment Tree Over Time
Uses:
hierarchical aggregation
+
time division
Complex algorithms often emerge from composing simpler patterns.
Common Mistakes
Copying Patterns Blindly
A successful divide-and-conquer algorithm depends on the combine step being efficient.
Do not copy merge sort's structure without analyzing merge cost.
Ignoring Data Layout
Recursive decomposition can improve asymptotic complexity while hurting cache behavior.
Overusing Recursion
Some problems are naturally iterative.
Do not force recursion where it provides no structural benefit.
Missing Alternative Decompositions
A problem may be divisible by:
position
value
time
geometry
answer space
Explore multiple possibilities.
Treating Patterns as Rules
Patterns are heuristics, not proofs.
Always analyze correctness and complexity separately.
Discussion
Divide and conquer is best understood as a family of design patterns rather than a single algorithmic technique. The surface details vary across sorting, geometry, algebra, and search, but the underlying structures repeat. Problems are partitioned into smaller pieces, recursive solutions exploit that structure, and a carefully designed combine step reconstructs the answer.
The practical skill is recognizing which decomposition is natural. Some problems divide by position, others by value, time, space, or candidate answers. Once the right decomposition is identified, the recurrence often becomes obvious. At that point, correctness proofs, complexity analysis, and implementation details become much easier to reason about.
The final section of this chapter brings these ideas together with a set of practical guidelines for choosing, designing, and implementing divide-and-conquer algorithms in real systems.