DSA Trainer
← All patterns
Pattern

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

sortmergesplitconquerhalfleft rightkth largestcount inversions

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.

Can I split the input in half and solve each half independently?
Is the brute force O(n²) because it considers every pair?
Does splitting the problem in half reduce the total work to O(n log n)?
Is the combination step cheap relative to the recursive solve?

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.

Start with Maximum Subarray

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.

  1. 1Identify the base case — the input small enough to solve directly (length 0 or 1).
  2. 2Identify the split point — usually the midpoint of the array or range.
  3. 3Recursively solve each half independently.
  4. 4Write the combine step — how do you build the full answer from the two half-answers?
  5. 5Verify the combination is correct for any two valid half-answers.
  6. 6Analyze: O(log n) levels × O(n) per combine = O(n log n).
B
Big_Wolverine_7575Founding Member· unprompted on Reddit

“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 Array

    Implement merge sort directly — the canonical divide and conquer algorithm.

    Coming soon
  • Kth Largest Element in an Array

    Quickselect: partition like quicksort but recurse only into the half containing the k-th element.

    Coming soon
  • Count of Smaller Numbers After Self

    Count inversions during a merge sort pass — each merge step reveals pairs out of order.

    Coming soon

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.

PatternUse when…
Divide and ConquerSubproblems are independent — the answer to one half doesn't affect or depend on the other half
Dynamic ProgrammingSubproblems 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).

Explore other patterns