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.
Split, solve the parts the same way, combine
Divide and conquer is recursion with a particular shape. Each call does three things:
- Divide
Split the input into smaller pieces of the same kind, usually two halves: the subproblems.
- Conquer
Solve each piece by calling the same function on it. A piece small enough to answer directly is the base case.
- 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.
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.
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.
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.
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.
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²).
4 questions
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.
Now solve some yourself
Only this topic 0 of 5 solved
- EasyThe value that fills more than half
- EasyA power modulo a prime, fast
- MediumEvery value an expression can take with brackets
- MediumFewest changes to make a string good by halves
- HardFewest strokes to paint a fence
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