Divide and Conquer Pattern
Split the problem in half, solve each half, combine the results.
Quick Summary
Best used when
- ✓The problem can be split into independent subproblems of the same type
- ✓The combination step is cheap relative to the split
- ✓You need O(n log n) and a pure O(n²) approach is too slow
- ✓The input is naturally divisible — arrays, trees, or ranges
Clue words in the problem
Complexity gain
O(n²) brute force comparison → O(n log n) recursive splitting
Why this pattern matters for LeetCode
Bubble sort and insertion sort compare every pair: O(n²). Merge sort splits the array in half, sorts each half, and merges: O(n log n). The insight is that two sorted halves can be merged in O(n) — you just compare the front of each. The splitting creates a logarithmic number of levels, and each level does O(n) total work. That's the divide and conquer payoff: log n levels × O(n) per level.
What the Divide and Conquer pattern is
Divide and conquer splits a problem into smaller subproblems, solves them recursively, and then combines their solutions. The three-step structure is always: Divide (split the input), Conquer (recursively solve each part), Combine (merge the results). The key requirement is that subproblems are independent — solving the left half doesn't affect the right half. Binary search is divide-and-conquer with only one branch; merge sort conquers both branches.
Reach for Divide and Conquer when you catch yourself thinking…
These are the internal questions that signal this pattern.
Beginner mental model
Think of sorting a deck of cards with a friend. Split the deck in half, each of you sorts your half independently. Then you merge: compare the top card of each pile, take the smaller one, repeat. You each worked on half the problem, and the merge is straightforward. That's merge sort. The key: your friend's work didn't depend on yours — the halves were independent.
Ready to practice Divide and Conquer?
Guided hints, not answers. You build real intuition.
When to use Divide and Conquer
- ✓Sorting arrays with merge sort (O(n log n) guaranteed)
- ✓Finding the k-th largest element with quickselect
- ✓Counting inversions in an array during a merge sort pass
- ✓Binary search is divide-and-conquer: discard one half and recurse into the other
- ✓Building a segment tree where each node represents a range
When NOT to use Divide and Conquer
- ✕The subproblems overlap and share results — that is Dynamic Programming, not divide and conquer
- ✕The combination step is O(n²) — splitting doesn't help if merging costs too much
- ✕The problem is sequential and each step depends on the previous one
- ✕Input size is small enough that O(n²) with low constant factors is faster
Better alternative: If subproblems overlap, use Memoization or Dynamic Programming. If the problem is sequential, a greedy or linear scan may work.
JavaScript code template
Merge sort — O(n log n) time, O(n) space
function mergeSort(arr) {
if (arr.length <= 1) return arr; // base case
const mid = Math.floor(arr.length / 2);
const left = mergeSort(arr.slice(0, mid)); // conquer left
const right = mergeSort(arr.slice(mid)); // conquer right
return merge(left, right); // combine
}
function merge(left, right) {
const result = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) result.push(left[i++]);
else result.push(right[j++]);
}
return result.concat(left.slice(i)).concat(right.slice(j));
}mergeSort divides the array at the midpoint and recurses on each half. The base case returns single-element arrays (already sorted). merge combines two sorted arrays in O(n) by comparing their front elements and taking the smaller one. The recursion tree has O(log n) levels; each level processes all n elements in total. O(n log n) total.
Step-by-step thinking process
Walk through this in your head before writing code.
- 1Identify the base case — the input small enough to solve directly (length 0 or 1).
- 2Identify the split point — usually the midpoint of the array or range.
- 3Recursively solve each half independently.
- 4Write the combine step — how do you build the full answer from the two half-answers?
- 5Verify the combination is correct for any two valid half-answers.
- 6Analyze: O(log n) levels × O(n) per combine = O(n log n).
“This app finally made it click. I tried NeetCode, CTCI, and YouTube for years and still couldn't solve Two Sum. The beginner mental models for the patterns are genuinely so helpful. THANK YOU.”
LeetCode-style problems that use this pattern
Practice on DSA Trainer with guided hints: no spoilers, just nudges.
Coming soon
- Sort an ArrayComing soon
Implement merge sort directly — the canonical divide and conquer algorithm.
- Kth Largest Element in an ArrayComing soon
Quickselect: partition like quicksort but recurse only into the half containing the k-th element.
- Count of Smaller Numbers After SelfComing soon
Count inversions during a merge sort pass — each merge step reveals pairs out of order.
Common mistakes beginners make
- ✕Confusing divide and conquer with dynamic programming — D&C subproblems are independent; DP subproblems overlap and share results. If the same subproblem appears in multiple branches, you need DP.
- ✕Expensive combine step — if merge is O(n²) instead of O(n), the total becomes O(n² log n), worse than O(n²). Make sure combining is at most O(n).
- ✕Off-by-one in the midpoint — use Math.floor(arr.length / 2). For ranges use left + Math.floor((right - left) / 2) to avoid overflow.
- ✕Not handling the base case — without a stopping condition the recursion bottoms out with zero-length arrays that still get passed to merge, producing empty slices rather than an error.
Divide and Conquer vs Dynamic Programming
Choose the right tool for the job.
| Pattern | Use when… |
|---|---|
| Divide and Conquer | Subproblems are independent — the answer to one half doesn't affect or depend on the other half |
| Dynamic Programming | Subproblems overlap — the same smaller problem is used by multiple larger problems and should be cached |
Time and space complexity
Time complexity
O(n log n) for merge sort; O(log n) for binary search
Space complexity
O(n) for merge sort (auxiliary arrays); O(log n) for recursion stack
The recursion tree has log₂(n) levels — at each level the array is halved. At each level, the total work across all subproblems is O(n) (every element is processed once in the combine step). log n levels × O(n) per level = O(n log n). The auxiliary space in merge sort is O(n) for the temporary arrays used during merging.
Ready to practice Divide and Conquer?
Guided hints, not spoilers. 150 problems across 33 patterns. Five are free, the rest unlock with a founding member seat.
Frequently asked questions
- Why is merge sort O(n log n) and not O(n²)?
- Because the work at each level of the recursion tree is O(n) total, not O(n) per subproblem. At level 1 you merge 2 halves of size n/2 — total work O(n). At level 2 you merge 4 quarters of size n/4 — still total work O(n). There are log n levels. n × log n total.
- How is divide and conquer different from dynamic programming?
- The key distinction is subproblem independence. D&C splits into independent halves — solving the left half has no effect on the right half. DP has overlapping subproblems — fib(5) appears in both fib(6) and fib(7). If you see the same sub-problem in multiple branches, you need DP (or memoization). If branches are truly independent, D&C is cleaner.
- Is binary search divide and conquer?
- Yes — binary search discards one half and recurses into the other. It's divide-and-conquer where the 'conquer' only processes one branch instead of both, which is why it's O(log n) instead of O(n log n).
- When does divide and conquer NOT improve performance?
- When the combine step is expensive. If merging two sorted halves cost O(n²) instead of O(n), the total would be O(n² log n) — worse than bubble sort. The pattern pays off only when combining is at most O(n).