A Systematic Approach to Algorithms

Vijay K. Garg · The University of Texas at Austin

Chapter 9. Divide and Conquer

Recurrence-driven algorithms: split, recurse on halves, combine. Parallel composition is what makes them fly.

This page: Classical forms. View LLP forms »

This page collects the classical / parallel-composition implementations of the divide-and-conquer algorithms developed in this chapter. The lattice-linear (LLP) reformulations and chapter setup live on the LLP companion page.

MergeSort (parallel)

MergeSort with the two recursive calls composed via [ ... [] ... ] — they are independent, so an LL backend can dispatch them in parallel. The Merge aux runs sequentially after both halves are sorted. The sequential variant lives in Chapter 4 (Sorting).

Time complexity: $O(n \log n)$, where $n$ is the size of the array.

QuickSort (parallel)

Lomuto-partition QuickSort. The two recursive calls on the left and right partitions are composed via [ ... [] ... ]; the partition step runs sequentially. The sequential variant lives in Chapter 4 (Sorting).

Time complexity: $O(n^2)$ worst case, $O(n \log n)$ on average, where $n$ is the size of the array.

ClosestPair

Plane-sweep closest-pair via divide and conquer. Points are pre-sorted by $x$-coordinate; the shared "best squared distance" register $G[0]$ flows through the recursion as an explicit parameter so the parallel branches see the same value.

Time complexity: $O(n \log^2 n)$, where $n$ is the number of points. (A further refinement — presorting the strip by $y$-coordinate once, outside the recursion — achieves $O(n \log n)$, but its pseudocode isn't given here.)

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 sequentially 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.

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 memoisation), Chapter 11 (network flow, where augmenting-path methods recurse on residual graphs), and the parallel-prefix / tree-contraction primitives that appear throughout the book's parallel chapters.