Push the head of each sorted list into a min-heap. Always poll() the global minimum → append to result → push its next node into the heap. Repeat until heap is empty.
🏔️ Min-Heap on Heads⚡ O(n log k)🔗 K Sorted ListsTime O(n log k)Space O(k)
K sorted arrays — same pattern, track (val, arrayIdx, elemIdx)
Push one head per list — heap size = K at all times
Poll min → result; push next from same list (if exists)
Kth smallest in sorted matrix — treat rows as K sorted lists
💡 Key insight: the heap always holds exactly K candidates (one per list). You only need to compare K numbers at a time, never all n. This gives O(log K) per operation vs O(K) for naive approach.
⚡ Complexity
Time
O(n log k)
Space
O(k)
n = total nodes across all K lists. Each node: one offer + one poll = O(log K).
Heap holds at most K nodes at any time → O(K) space.
Compare: merge two-at-a-time = O(n log k) but O(n) space.
Naive (compare all K heads) = O(nK) — much worse for large K.
Live Animation · K-Way Merge · LC #23
Problem
Given K = 3 sorted linked lists, merge them into one sorted list. Push each list's head into a min-heap. Always poll the global minimum, append to result, then push its next node. Each poll is O(log K) — total O(n log K) for n elements across K lists.
Input: L1 = [1,4,7], L2 = [2,5,8], L3 = [3,6,9] · Answer: [1,2,3,4,5,6,7,8,9]
🏔️ Min-Heap (current heads) ⬇️ min = next to merge
Push heads to initialize…
📤 Merged Result
—
🔀 K-Way Merge: Push the head of each sorted list into a min-heap. Always poll the global minimum, then push the next node from that list. O(n log K) for n total nodes across K lists.
PriorityQueue<ListNode> pq = new PriorityQueue<>((a,b) -> a.val - b.val);
🧩 Pattern Skeleton Java 8
// K-Way Merge — min-heap holds current heads ─────────────────PriorityQueue<ListNode> pq = newPriorityQueue<>(
(a, b) -> a.val - b.val); // min-heap by valuefor (ListNode list : lists) // push head of each listif (list != null) pq.offer(list);
ListNode dummy = newListNode(0), curr = dummy;
while (!pq.isEmpty()) {
ListNode node = pq.poll(); // global minimum
curr.next = node;
curr = curr.next;
if (node.next != null) // push next from same list
pq.offer(node.next);
}
return dummy.next;
// For sorted arrays: track (value, arrayIdx, elemIdx)PriorityQueue<int[]> pq2 = newPriorityQueue<>((a,b) -> a[0]-b[0]);