Chapter 9. Divide and Conquer
Recurrence-driven algorithms: split, recurse on halves, combine.
This page: Classical forms. View LLP forms »
This page collects the classical implementations of the divide-and-conquer algorithms developed in this chapter, matching the book's presentation. The lattice-linear (LLP) reformulations and chapter setup live on the LLP companion page.
ClosestPair
Plane-sweep closest-pair via divide and conquer. Points are pre-sorted once by $x$-coordinate and by $y$-coordinate; the shared "best squared distance" register $G[0]$ flows through the recursion as an explicit parameter, along with $Ys$, this range's points in $y$-order. Each call splits its inherited $y$-order between the two halves and reads the strip off it already sorted, so no level re-sorts. The two recursive calls run one after the other.
Time complexity: $O(n \log n)$, where $n$ is the number of points: $O(n \log n)$ for the two presorts, then $T(n) = 2T(n/2) + O(n)$ for a recursion whose divide and combine steps are both linear scans of the inherited $y$-order.
CountingInversions
Counts inversions $(i, j)$ with $i < j$ and $A[i] > A[j]$ via the MergeSort framework. The merge step counts cross-half inversions for free; total time $O(n \log n)$.
Time complexity: $O(n \log n)$, where $n$ is the size of the array.
Karatsuba
Karatsuba's $O(n^{\log_2 3})$ integer multiplication. Three half-size multiplications ($x_0 y_0$, $x_1 y_1$, $(x_0 + x_1)(y_0 + y_1)$) instead of four; combine by subtracting two of the products from the third.
Time complexity: $\Theta(n^{\log_2 3}) \approx \Theta(n^{1.585})$ for $n$-digit inputs.
Planar Convex Hull
Sort the points by $x$-coordinate and split at the median into $P_L$ and $P_R$; the two recursive sub-hulls are merged via their upper and lower common tangents, each determinable in $O(n)$ time.
Time complexity: $O(n \log n)$, where $n$ is the number of points.
Strassen
Strassen's matrix multiplication. Instead of the 8 recursive multiplications a naive block decomposition needs, 7 intermediate products $M_1, \ldots, M_7$ suffice, trading one multiplication for a handful of extra additions and subtractions.
The book writes the quadrant arithmetic infix — $\textsf{Strassen}(A_{11} + A_{22},\,
B_{11} + B_{22})$ and $C_{11} := M_1 + M_4 - M_5 + M_7$ — which needs a matrix type
carrying operators. The program below represents a matrix as an
int[][] instead, so those sums nest add()/sub()
calls; quadrant() extracts the four blocks and combine()
reassembles them. Everything else follows the algorithm box step for step.
Time complexity: $O(n^{\log_2 7}) \approx O(n^{2.807})$ for $n \times n$ matrices ($n$ a power of 2).
FFT
The recursive Fast Fourier Transform evaluates a coefficient vector at the $N$-th roots of unity by splitting on parity of index and combining via the butterfly identity $\hat{a}_k = A_e(\omega^{2k}) + \omega^k A_o(\omega^{2k})$, $\hat{a}_{k+N/2} = A_e(\omega^{2k}) - \omega^k A_o(\omega^{2k})$. Applying the forward transform to two coefficient vectors, multiplying pointwise, and inverse-transforming back gives $O(n \log n)$ polynomial multiplication.
Time complexity: $O(N \log N)$, where $N$ is the (padded, power-of-2) transform length.
Looking ahead
Divide-and-conquer recurrences underpin Chapter 10 (dynamic programming, where overlapping subproblems force memoization) and Chapter 11 (network flow, where augmenting-path methods recurse on residual graphs).