Divide & conquer

Split the problem into halves, solve each half the same way, and combine the answers. How many halves you solve and how much the combining costs decide the whole running time.

3 examples10 to practiceRead · 5 min
The idea

Split, solve the parts the same way, combine

Divide and conquer is recursion with a particular shape. Each call does three things:

  1. Divide

    Split the input into smaller pieces of the same kind, usually two halves: the subproblems.

  2. Conquer

    Solve each piece by calling the same function on it. A piece small enough to answer directly is the base case.

  3. Combine

    Build the answer for the whole input from the pieces' answers.

Binary search is the smallest example: it divides the range in two, conquers only the half that can hold the target, and has nothing to combine. Finding the largest item is the next one up.

Both halves

Finding the largest item by halves solves both halves and keeps the bigger answer

The largest item of a list is the larger of the left half's largest and the right half's largest. A one-item range is its own largest item. That is a complete divide-and-conquer algorithm:

Eight items made 15 calls: 8 one-item base cases and 7 combines, one for each pair of answers joined. A loop would also do 7 comparisons. Divide and conquer doesn't make this problem faster; it is here because the shape is easy to see. The payoff comes when combining two sorted halves, or skipping a half, beats working on the whole.

One half

When one half's answer gives you the other's, the work drops to O(log n)

Computing x¹⁰ by multiplying 10 copies of x takes 9 multiplications. But x¹⁰ = x⁵ × x⁵: compute x⁵ once, square it, and you have halved the problem. For an odd power, multiply in one more x: x⁵ = x² × x² × x.

Each call halves n, so the depth is about log₂ n, and each level does one or two multiplications. Raising a number to the millionth power takes about 20 levels instead of a million multiplications. The two halves were identical, so solving one was enough.

Hard

The answer may cross the middle

The best run in a range is either entirely in the left half, entirely in the right half, or crosses the middle. The first two are smaller copies of the problem. The crossing one is cheap: the best run ending at the middle plus the best run starting just after it, found by walking outward. That is T(n) = 2T(n ÷ 2) + O(n): O(n log n). A single pass solves this problem in O(n) (Dynamic programming: basics); here it shows how the crossing case works.

The cost

A recurrence describes the cost, and its shape gives the answer

The running time of a divide-and-conquer algorithm is easiest to write the way the algorithm itself is written: in terms of smaller copies of itself. That equation is a recurrence. For the largest item, T(n) = 2T(n ÷ 2) + O(1): two half-size calls plus a constant amount of combining.

Recurrence

Total

Example

T(n) = T(n ÷ 2) + O(1)

O(log n)

binary search, fast power

T(n) = 2T(n ÷ 2) + O(1)

O(n)

largest item by halves

T(n) = 2T(n ÷ 2) + O(n)

O(n log n)

merge sort

T(n) = T(n − 1) + O(n)

O(n²)

a split that peels off one item at a time

Read the totals off the recursion tree. With halves, it is about log₂ n levels deep. If the work at each level adds up to O(n), as when every item is touched once per level, the total is O(n log n). If only one call is made per level and it does constant work, the total is just the depth, O(log n).

The rule

Divide and conquer pays off when the pieces are roughly equal and combining is cheap. Equal halves give about log n levels; an uneven split that peels off one item at a time gives n levels, and the advantage is gone.

Where it leads

The fastest general sorts are divide and conquer

The next page uses this shape twice. Merge sort splits the list in half, sorts both halves and merges them, which is the T(n) = 2T(n ÷ 2) + O(n) row: O(n log n). Quicksort does the splitting work first, around a chosen item, and then needs no combining at all. Its risk is the last row of the table: a bad split, repeated, makes it O(n²).

Check yourself

4 questions

1. What are the three steps of divide and conquer?
2. Fast power computes x¹⁰⁰⁰⁰⁰⁰ in about how many levels of calls?
3. An algorithm makes two half-size calls and then does O(n) work to combine them. What is its running time?
4. A divide step always splits off just one item and leaves the rest as the other piece, then does O(n) work. What happens to the cost?
Takeaways

Remember this

  • Divide and conquer splits a problem into smaller copies, solves them the same way and combines the answers.
  • A recurrence such as T(n) = 2T(n ÷ 2) + O(n) describes the cost; the recursion tree's depth and work per level give the total.
  • One half-size call with constant work is O(log n); two with linear combining is O(n log n).
  • The split must be roughly even: peeling off one item at a time gives n levels and loses the advantage.
Practice

Now solve some yourself

Only this topic 0 of 5 solved

  1. Easy
    The value that fills more than half
    Divide & conquer
  2. Easy
    A power modulo a prime, fast
    Divide & conquer
  3. Medium
    Every value an expression can take with brackets
    Divide & conquer
  4. Medium
    Fewest changes to make a string good by halves
    Divide & conquer
  5. Hard
    Fewest strokes to paint a fence
    Divide & conquer

Mixed with topics you have practiced 0 unlocked

    5 more once you have practiced Binary trees & BSTs, Linked lists, Merge sort & quicksort. Play one of its examples to the end and solve one of its problems to unlock them.

    Problems open on their own sites (LeetCode, Codeforces, CodeChef, AtCoder, CSES) in a new tab. Tick Solved when you get it accepted there; your ticks decide which mixed problems open next.

    Next

    Merge sort & quicksort

    Continue