44. Merge k Sorted Lists
You are given k linked lists, each sorted ascending. Merge them into one sorted list and return its head.
Example 1
Input:
lists = [[1,4,5],[1,3,4],[2,6]]Output:
[1,1,2,3,4,4,5,6]Example 2
Input:
lists = []Output:
[]Hint 1
At each step you need the smallest of k current heads.
Hint 2
A min-heap of size k gives it in O(log k).
Approach 1: Merge one by one
Merge list 1 with 2, the result with 3, and so on.
⏱ Time O(N · k)💾 Space O(1)
Approach 2: Min-heap of heads
Pop the smallest head and push its successor.
⏱ Time O(N log k)💾 Space O(k)
Approach 3: Divide and conquer ✅
Merge pairs of lists in rounds.
⏱ Time O(N log k)💾 Space O(log k)
Reference solution for Divide and conquer (time O(N log k), space O(log k)). Each solution passes every test in all four languages.
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
heap = [(node.val, i, node) for i, node in enumerate(lists) if node]
heapq.heapify(heap) # i breaks ties so nodes are never compared
dummy = tail = ListNode()
while heap:
_, i, node = heapq.heappop(heap) # smallest head among all lists
tail.next = tail = node
if node.next:
heapq.heappush(heap, (node.next.val, i, node.next))
return dummy.nextclass Solution {
public ListNode mergeKLists(ListNode[] lists) {
PriorityQueue<ListNode> heap = new PriorityQueue<>((a, b) -> Integer.compare(a.val, b.val));
for (ListNode n : lists) if (n != null) heap.offer(n);
ListNode dummy = new ListNode(), tail = dummy;
while (!heap.isEmpty()) {
ListNode node = heap.poll(); // smallest head among all lists
tail.next = node;
tail = node;
if (node.next != null) heap.offer(node.next);
}
return dummy.next;
}
}class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
auto cmp = [](ListNode* a, ListNode* b) { return a->val > b->val; };
priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> heap(cmp);
for (ListNode* n : lists) if (n) heap.push(n);
ListNode dummy, *tail = &dummy;
while (!heap.empty()) {
ListNode* node = heap.top(); heap.pop(); // smallest head among all lists
tail->next = node;
tail = node;
if (node->next) heap.push(node->next);
}
return dummy.next;
}
};class MinHeap {
constructor(less = (a, b) => a < b) { this.a = []; this.less = less; }
get size() { return this.a.length; }
peek() { return this.a[0]; }
push(x) { const a = this.a; a.push(x); let i = a.length - 1;
while (i > 0) { const p = (i - 1) >> 1; if (!this.less(a[i], a[p])) break; [a[i], a[p]] = [a[p], a[i]]; i = p; } }
pop() { const a = this.a, top = a[0], last = a.pop();
if (a.length) { a[0] = last; let i = 0;
while (true) { const l = 2 * i + 1, r = l + 1; let m = i;
if (l < a.length && this.less(a[l], a[m])) m = l;
if (r < a.length && this.less(a[r], a[m])) m = r;
if (m === i) break; [a[i], a[m]] = [a[m], a[i]]; i = m; } }
return top; }
}
function mergeKLists(lists) {
const heap = new MinHeap((a, b) => a.val < b.val);
for (const n of lists) if (n) heap.push(n);
const dummy = new ListNode();
let tail = dummy;
while (heap.size) {
const node = heap.pop(); // smallest head among all lists
tail.next = node;
tail = node;
if (node.next) heap.push(node.next);
}
return dummy.next;
}Try solving it yourself first. Interviewers care more about how you explain the approach than about the finished code.
Watch the core idea of this problem step by step. Change the input and press Visualize.
Explained in the lesson Heaps & Priority Queues.
Run your code to see results here.