9: Divide and Conquer
Divide and conquer breaks problems into smaller subproblems, solves them recursively, and combines solutions. The challenge: analyzing recurrences to prove efficiency.
The Divide and Conquer Paradigm
Steps:
- Divide the problem into smaller subproblems
- Conquer each subproblem recursively
- Combine solutions to solve the original problem
Key insight: Subproblems must be substantially smaller (often half the size) for efficiency gains.
Merge Sort
Algorithm
MergeSort(A, lo, hi):
if lo < hi:
mid = (lo + hi) / 2
MergeSort(A, lo, mid)
MergeSort(A, mid+1, hi)
Merge(A, lo, mid, hi)Merge operation: Combine two sorted halves in time by comparing front elements.
Recurrence Analysis
Recursion tree method:
- Level 0: work (one problem of size )
- Level 1: work (two problems of size )
- Level : work ( problems of size )
- Height: levels
Total:
Counting Inversions
Problem Definition
Given array , count pairs where but .
Applications: Measuring similarity between rankings (e.g., collaborative filtering).
Brute Force
Check all pairs:
Divide and Conquer Approach
Key insight: Inversions come in three types:
- Both elements in left half
- Both elements in right half
- One in each half (split inversions)
Algorithm:
CountInversions(A):
if |A| = 1: return 0
Split A into L and R
(L', countL) = CountInversions(L)
(R', countR) = CountInversions(R)
(A', countSplit) = MergeAndCount(L', R')
return countL + countR + countSplitMergeAndCount: During merge, when we take from right array, count remaining elements in left array (all form inversions).
Master Theorem
For recurrences of the form where , :
Let
Case 1: If where , then
Case 2: If , then
Case 3: If where , and for some , then
Intuition
Compare (combine work) to (recursive work):
- Case 1: Recursion dominates → total is
- Case 2: Equal work at each level → multiply by
- Case 3: Combine dominates → total is
Examples
| Recurrence | Case | |||||
|---|---|---|---|---|---|---|
| 2 | 2 | 1 | 2 | |||
| 4 | 2 | 2 | 1 | |||
| 4 | 2 | 2 | 3 | |||
| 3 | 2 | 1 |
Closest Pair in
Problem Definition
Given points in the plane, find the pair with minimum Euclidean distance.
Brute force:
Algorithm
ClosestPair(P):
Sort P by x-coordinate → Px
Sort P by y-coordinate → Py
return ClosestPairRec(Px, Py)
ClosestPairRec(Px, Py):
if |Px| ≤ 3: return brute force
Divide Px into left half Lx and right half Rx
Construct Ly, Ry from Py (preserving y-order)
δL = ClosestPairRec(Lx, Ly)
δR = ClosestPairRec(Rx, Ry)
δ = min(δL, δR)
δS = ClosestSplitPair(Px, Py, δ)
return min(δ, δS)The Key Insight: The -Strip
For split pairs, both points must be within distance of the dividing line.
Crucial lemma: In the -strip sorted by -coordinate, we only need to check each point against the next 7 points.
Why 7? Partition the strip into boxes. Each box contains at most one point (otherwise we’d have found a closer pair). A rectangle contains at most 8 points.
ClosestSplitPair(Px, Py, δ):
x* = rightmost x-coordinate in left half
S = points in Py with x ∈ [x* - δ, x* + δ]
best = δ
for i = 1 to |S|:
for j = 1 to min(7, |S| - i):
best = min(best, dist(S[i], S[i+j]))
return bestRunning Time
The initial sorting is . Maintaining sorted order during recursion is per level.
Karatsuba’s Algorithm (Integer Multiplication)
Problem
Multiply two -digit integers and .
Grade school: single-digit multiplications.
Divide and Conquer Attempt
Write and where have digits.
Naive: 4 recursive multiplications →
Karatsuba’s Insight
Compute using only one multiplication:
So:
Algorithm:
- Compute (one multiplication)
- Compute (one multiplication)
- Compute (one multiplication)
- Compute (subtraction)
By Master Theorem (Case 1):
Strassen’s Algorithm (Matrix Multiplication)
Problem
Multiply two matrices and .
Standard: operations.
Block Matrix Multiplication
Partition into submatrices:
Naive: 8 recursive multiplications →
Strassen’s Insight
Reduce to 7 multiplications using clever linear combinations:
Then:
Median and Selection
Problem
Given unsorted array of distinct elements, find the -th smallest element.
Special case: Median when .
Sorting: — can we do better?
QuickSelect (Randomized)
QuickSelect(A, k):
if |A| = 1: return A[1]
Choose pivot p uniformly at random
Partition A into:
L = elements < p
R = elements > p
if k ≤ |L|:
return QuickSelect(L, k)
else if k = |L| + 1:
return p
else:
return QuickSelect(R, k - |L| - 1)Expected time:
Worst case: (bad pivot choices)
Deterministic Selection (Median of Medians)
Goal: Find a pivot guaranteed to eliminate a constant fraction of elements.
Select(A, k):
if |A| ≤ 5: sort and return k-th element
Divide A into groups of 5
Find median of each group
p = Select(medians, ⌈|medians|/2⌉) // Median of medians
Partition A around p into L and R
Recurse on appropriate sideAnalysis
Key insight: At least elements are , and at least elements are .
- About groups
- Half of groups have median
- Each such group contributes at least 3 elements
So .
Claim:
Proof: Guess and verify:
For : ✓
Summary
| Problem | Algorithm | Time Complexity |
|---|---|---|
| Sorting | Merge Sort | |
| Counting Inversions | Modified Merge Sort | |
| Closest Pair | Divide by x-coord | |
| Integer Multiplication | Karatsuba | |
| Matrix Multiplication | Strassen | |
| Selection | Median of Medians |
The power of divide and conquer: Reducing the number of subproblems (Karatsuba: 4→3, Strassen: 8→7) yields asymptotic improvements.