#23 Merge k Sorted Lists
frequently reported atNVIDIAMetaOracleAmazonByteDance / TikTokApple
the problem
In plain words
Merge k sorted linked lists into one sorted linked list and return its head.
in lists = [[1,4,5],[1,3,4],[2,6]]
out [1,1,2,3,4,4,5,6]
in lists = []
out []
in lists = [[]]
out []
- 0 ≤ k ≤ 10⁴
- 0 ≤ lists[i].length ≤ 500
- -10⁴ ≤ value ≤ 10⁴
- Each list is sorted; total nodes ≤ 10⁴
your turn
Try it before you peek
Read the examples, say the brute force out loud, then write code: here or on LeetCode ↗. Stuck for 20 minutes? Open one hint at a time.
Solve it in the browser
LeetCode-style: complete the class. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
Solutions are hidden so you can try first. Even 20 minutes of real effort makes the answer stick far better than reading it.
Marking the problem solved, or opening every hint, also shows it.
the aha
Key insight
patternK-way mergeDivide and conquer
The next node of the result is always the smallest of the k current heads. A min-heap of the k heads finds it in O(log k).
solutions
From brute force to optimal
Dump all values in a list, sort, rebuild.
- Walk all lists into an ArrayList.
- Sort.
- Build a new list.
N = total nodes; ignores that the lists were already sorted.
Values plus new nodes.
class Solution { public ListNode mergeKLists(ListNode[] lists) { List<Integer> all = new ArrayList<>(); for (ListNode head : lists) for (ListNode n = head; n != null; n = n.next) all.add(n.val); Collections.sort(all); ListNode dummy = new ListNode(0), tail = dummy; for (int v : all) tail = tail.next = new ListNode(v); return dummy.next; }}result = merge(result, list) for each list.
- Two-list merge from the linked-lists chapter.
- Fold it over all k lists.
The growing result is re-walked k times.
Relinks existing nodes.
class Solution { public ListNode mergeKLists(ListNode[] lists) { ListNode merged = null; for (ListNode list : lists) merged = merge(merged, list); // the result keeps growing return merged; } static ListNode merge(ListNode a, ListNode b) { ListNode dummy = new ListNode(0), tail = dummy; while (a != null && b != null) { if (a.val <= b.val) { tail.next = a; a = a.next; } else { tail.next = b; b = b.next; } tail = tail.next; } tail.next = a != null ? a : b; return dummy.next; }}Poll the smallest head, append it, offer its next node.
- Offer every non-null head.
- Poll → append to the tail.
- If it has a next, offer that.
Every node is offered and polled once on a heap of ≤ k.
The heap holds one node per list.
class Solution { public ListNode mergeKLists(ListNode[] lists) { PriorityQueue<ListNode> heap = new PriorityQueue<>(Comparator.comparingInt(n -> n.val)); for (ListNode head : lists) if (head != null) heap.offer(head); // one candidate per list ListNode dummy = new ListNode(0), tail = dummy; while (!heap.isEmpty()) { ListNode smallest = heap.poll(); // smallest of all current heads tail = tail.next = smallest; if (smallest.next != null) heap.offer(smallest.next); // its list's next candidate } return dummy.next; }}Dry run
Merge lists in pairs: k → k/2 → k/4 … → 1.
- gap = 1, 2, 4, …
- Merge lists[i] with lists[i + gap].
log k rounds, each touching every node once.
Iterative, relinks nodes in place.
class Solution { public ListNode mergeKLists(ListNode[] lists) { if (lists.length == 0) return null; for (int gap = 1; gap < lists.length; gap *= 2) { // pair up lists: 1+1, 2+2, 4+4… for (int i = 0; i + gap < lists.length; i += 2 * gap) { lists[i] = merge(lists[i], lists[i + gap]); } } return lists[0]; } private static ListNode merge(ListNode a, ListNode b) { // the classic two-list merge ListNode dummy = new ListNode(0), tail = dummy; while (a != null && b != null) { if (a.val <= b.val) { tail.next = a; a = a.next; } else { tail.next = b; b = b.next; } tail = tail.next; } tail.next = a != null ? a : b; return dummy.next; }}in the room
How to say it in the interview
talk track
- Start from merging two lists, then ask: how do I pick the smallest of k heads fast? → heap.
- Mention divide and conquer as the O(1)-space alternative.
traps
- Offering null heads (empty lists) — PriorityQueue throws on null.
- Comparator
(a, b) -> a.val - b.val— fine for these bounds, but prefercomparingInt.
what they ask next
Follow-ups
Kth Smallest Element in a Sorted Matrix (LC 378)?
Same k-way merge: rows are sorted lists; poll k times from a heap of row cursors.
before you submit
Edge cases to test
- lists = [] or lists = [[]]: return null.
- Empty lists mixed in: never offer null — PriorityQueue throws NullPointerException.
- Equal values from different lists may come out in either order; both are correct.
practise next
Similar problems
- #21Merge Two Sorted ListsEasyin Linked Lists
- #148Sort ListMediumin Sorting
- #373Find K Pairs with Smallest SumsMediumin Heaps
- #632Smallest Range Covering Elements from K ListsHardin Heaps