2Brute2Best
πŸ”₯0

Merge K Sorted Arrays

MediumΒ·GeeksforGeeksBasic Anchor
GeeksforGeeks
30-Second Mental ModelK-way Merge β€” Merge K sorted (heap with one front per list)
Complexity:O(N log N)β†’O(N log K)
Key Insight

Keep one candidate per array in a min-heap: its first unused element. Pop the smallest candidate and output it. Then push the next element from the same array. The heap never holds more than K items, because each array contributes only one candidate at a time.

Core Validity Invariant

The smallest unused element overall is always the smallest of the first unused elements of the arrays, so the heap top is always the correct next output.

01

Problem

You get K arrays. Each array is already sorted from smallest to largest. The arrays can have different lengths, and one of them can be empty.

Merge them into one array that holds every element, in sorted order.

Input

arr: a list of K sorted arrays. K: how many arrays there are.

Output

One sorted array that holds every element of every input array.

Example 1
Input: arr = [[2, 6, 9], [1, 5, 8], [0, 3, 4, 7]], K = 3
Output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

The smallest front value is 0 (from the third array), then 1, then 2, and so on. All 10 elements end up in order.

Example 2
Input: arr = [[1, 3], [], [2]], K = 3
Output: [1, 2, 3]

The empty array has nothing to add, so it is skipped.

Constraints
  • β€’ Each input array is sorted from smallest to largest.
  • β€’ The arrays can have different lengths, and an array can be empty.
  • β€’ The values are integers.
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck β€” each hint is counted.

  1. 1.

    Each array is already sorted. Which element can be the very next one I output?

  2. 2.

    If I only look at the first unused element of each array, how many candidates do I have at any moment?

  3. 3.

    After I take an element out of an array, which element of that same array becomes a candidate?

  4. 4.

    Which data structure gives me the smallest of my candidates quickly, and how big does it need to be?

  5. 5.

    If I put all N elements into that structure at the start, does it still do the job?

03

Brute force approach

04

Better approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceCopy every element into one list, then sort the whole listO(N log N)O(N)
BetterMerge the result with the next array, like merge sort's merge stepO(N Β· K)O(N)
OptimalKeep the first unused element of each array in a min-heap; pop the smallest, then push its successorO(N log K)O(K)
09

Why does this belong to this pattern?

Clues in the problem statement
  • β€œK sorted arrays”Each array is sorted, so only its first unused element can be the next output from it. That is why K candidates are enough.
  • β€œmerge into one sorted array”At every step, take the smallest of the candidates β†’ a min-heap of the front values.
  • β€œevery element appears once”Each element is pushed and popped once, so the cost is N pushes and pops, not one per array.
K sorted lists+need the smallest current front each time+heap of K fronts→K-way Merge — Merge K sorted (heap with one front per list)

Merging two sorted arrays needs one comparison per step: the two fronts. With K arrays, the next value is the smallest of K fronts, so we keep a min-heap of K candidates. The key move is pop, then push that array's successor. Push nothing else. Merge K Sorted Lists uses the same heap on linked lists, and Sort a Nearly Sorted Array uses it with a window of k + 1 items.

10

Don't make this mistake

Pushing every element into the heap (pattern confusion)
βœ— for (int i = 0; i < K; i++) for (int x = 0; x < (int)arr[i].size(); x++) pq.push(Item(arr[i][x], i, x));
βœ“ for (int i = 0; i < K; i++) if (!arr[i].empty()) pq.push(Item(arr[i][0], i, 0));

The output is still sorted, so this looks right. But the heap now starts with all 10 elements instead of 3. That is just heap sort, O(N log N), and it throws away the idea that each array offers one candidate at a time. Push only the first element of each array.

Comparator direction: priority_queue is a max-heap by default
βœ— priority_queue<Item> pq;
βœ“ priority_queue<Item, vector<Item>, greater<Item>> pq;

On the dry run the heads are 2, 1 and 0. A max-heap pops 2 first, then keeps taking the largest head from each array. It outputs 2 6 9 1 5 8 0 3 4 7, which is not sorted. greater<> turns the heap into a min-heap.

Forgetting to push the successor
βœ— auto [v, i, j] = pq.top(); pq.pop(); result.push_back(v); // nothing pushed for array i
βœ“ auto [v, i, j] = pq.top(); pq.pop(); result.push_back(v); if (j + 1 < (int)arr[i].size()) pq.push(Item(arr[i][j + 1], i, j + 1));

The heap only ever holds the first unused element of each array. Without the push, it empties after 3 pops. On the dry run the output would be just [0, 1, 2].

Reading the first element of an empty array
βœ— for (int i = 0; i < K; i++) pq.push(Item(arr[i][0], i, 0));
βœ“ for (int i = 0; i < K; i++) if (!arr[i].empty()) pq.push(Item(arr[i][0], i, 0));

An empty array has no element 0. Reading it is undefined behaviour and often crashes. Check the size before reading the first element.

11

Want to implement this?

Write it yourself on GeeksforGeeks, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like K-way Merge translate into production architectures and low-level memory mechanics.