ben's notes

Divide and Conquer (Master Theorem)

Divide and Conquer: an Intro #

Sometimes, especially for recursive algorithms, we can write a runtime as a recurrence relation: that is, part of a function’s runtime definition is the function itself with a smaller problem size.

This applies directly to a method called divide and conquer, which goes something like this:

  • We’re given some input $x$ and are trying to evaluate a function $A(x)$.
  • We can split $x$ into smaller parts $x_1, x_2, \cdots x_a$.
  • We can then find the output of each individual part $A(x_1), A(x_2), \cdots A(x_a)$.
  • Sum up all of these outputs to get the original desired value $A(x)$.

Take this example (Karatsuba Multiplication): $T(n) = 3T(n/2) + cn$

The General Form #

$$ T(n) = a \cdot T(\frac{n}{b}) + c \cdot n^d $$

$a$, $b$ and $c$ are constants and $T(n)$ is the total amount of work that must be done for an input size of $n$.

Master Theorem for Recurrences #

Root Heavy

$$ \frac{a}{b^d} < 1 \implies T(n) = O(n^d) $$

Balanced

$$ \frac{a}{b^d}= 1 \implies T(n) = O(n^dlog(n)) $$

Leaf Heavy

$$ \frac{a}{b^d} > 1 \implies T(n) = O(n^{log_b(a)}) $$

Proof:

Here’s a chart of how the problem evolves down the layers. At the end, we will need to calculate $T(1)$, which is assumed (without loss of generality) to be a constant work per problem $c$.

If we sum up all of the total work per layer, we get the expression:

$$ T(n) = c \cdot n^d(1 + \frac{a}{b^d} + \cdots + (\frac{a}{b^d})^{log(b)^n}) $$

There are three cases (as shown above). We can split them now to evaluate this sum.

Root Heavy: $a/b^d < 1$, so $d > log_b(a)$.

Recall that $1 + p + p^2 + \cdots + p^k = \frac{p^{k+1}-1}{p-1}$ by the geometric series formula.

So:

$$ T(n) = c \cdot n^d(\frac{1-(a/b^d)^{log_b(n)+1}}{1-a/b^d}) $$

which simplifies to $O(n^d)$ since the geometric series converges to a constant when $a/b^d < 1$.

Balanced: $a/b^d = 1$.

This means that the work for each layer must be $1$ because $\frac{a}{b^d} = \frac{a}{b^{log_b(a)}} = \frac{a}{a}$.

Since there are $log_b(n)$ layers, the total work done must be $c \cdot n^d (log_b(n)) \implies O(n^d log_b(n))$.