150NeetCode 150

44.Merge K Sorted Lists

HardBlind 75Linked List ยท 10/11

Problem

You are given an array of k linked lists lists, each sorted in ascending order.

Merge all of them into one sorted linked list and return its head.

Examples

Input:  lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
Explanation: All values from the three sorted lists, merged in order.
Input:  lists = []
Output: []
Input:  lists = [[]]
Output: []
Explanation: One list, and it is empty.

Constraints

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i] is sorted in ascending order.
  • The sum of lists[i].length will not exceed 10^4.

๐Ÿ’ก Key Insight

Let N be the total number of nodes. Merging lists one at a time re-walks the growing result k times (O(kN)). To get O(N log k), either keep the k current heads in a min-heap (each pop/push costs O(log k)), or merge lists in pairs like merge sort โ€” each round halves the number of lists, so there are only log k rounds and each touches every node once.

Brute Force (Collect and Sort)

TimeO(N log N)SpaceO(N)

Intuition

Throw every value into one array, sort it, and build a fresh list. It ignores that the inputs are sorted.

Algorithm

  1. Walk every list, adding each val to values.
  2. Sort values.
  3. Build a new list from the sorted values with a dummy head.

Visualization

[1,4,5] [1,3,4] [2,6]
collect: [1,4,5,1,3,4,2,6]
sort:    [1,1,2,3,4,4,5,6] -> build list

Code

java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        List<Integer> values = new ArrayList<>();
        for (ListNode list : lists) {
            for (ListNode n = list; n != null; n = n.next) {
                values.add(n.val);
            }
        }
        Collections.sort(values);
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        for (int v : values) {
            tail.next = new ListNode(v);
            tail = tail.next;
        }
        return dummy.next;
    }
}

Complexity

  • Time: O(N log N) โ€” sorting all values.
  • Space: O(N) โ€” the values array and the new list.

Complexity Comparison

Approach Time Space
Collect and Sort O(N log N) O(N)
Merge One by One O(k ยท N) O(1)
Min-Heap O(N log k) O(k)
Divide and Conquer O(N log k) O(1)

Common Pitfalls

  • Pushing null heads into the priority queue โ€” the comparator throws a NullPointerException; skip empty lists.
  • Returning lists[0] without checking k == 0 โ€” an empty array throws ArrayIndexOutOfBoundsException.
  • Writing the comparator as a.val - b.val is safe here (values are small) but Integer.compare avoids overflow habits in general.
  • Assuming merge-one-by-one is O(N log k) โ€” the growing result list makes it O(kN).
  • In divide and conquer, stepping i by interval instead of 2 * interval, which merges the same list twice.