LeetCode - Merge k Sorted Lists

2 minute read

Problem description

description

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

Example:

1
2
3
4
5
6
7
Input:
[
  1->4->5,
  1->3->4,
  2->6
]
Output: 1->1->2->3->4->4->5->6

Analysis

This is a standard merge k list. At first, we can add first element of every list into a PriorityQueue, and we poll the smallest one and add the next ListNode of it into the PriorityQueue.

Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class MergekSortedLists {
  public ListNode mergeKLists(ListNode[] lists) {
    ListNode dummy = new ListNode(0);

    int len = lists.length;
    PriorityQueue<ListNodeWrapper> pq = new PriorityQueue<>(new Comparator<ListNodeWrapper>() {
      @Override
      public int compare(ListNodeWrapper o1, ListNodeWrapper o2) {
        return o1.listNode.val - o2.listNode.val;
      }
    });

    for (int i = 0; i < len; i++){
      // wrong for this
      if (lists[i] != null){
        pq.offer(new ListNodeWrapper(lists[i], i));
      }
    }
    ListNode p = dummy;
    while (!isReachEnd(lists)){
      ListNodeWrapper next = pq.poll();
      int index = next.index;
      p.next = next.listNode;
      p = p.next;
      lists[index] = lists[index].next;
      if (lists[index] != null){
        pq.offer(new ListNodeWrapper(lists[index], index));
      }
    }

    return dummy.next;
  }

  boolean isReachEnd(ListNode[] lists){
    for(ListNode listNode:lists){
      if (listNode != null){
        return false;
      }
    }

    return true;
  }

  class ListNodeWrapper{
    ListNode listNode;
    int index;

    public ListNodeWrapper(ListNode l, int i){
      listNode = l;
      index = i;
    }
  }
}

Another solution from LeetCode is to use a divide and conquer method to divide the K lists into several groups of two lists and do the merge.

Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        return mergeHelper(lists, 0, lists.length - 1);
    }
    
    private ListNode mergeHelper(ListNode[] lists, int start, int end) {
        if (start == end) {
            return lists[start];
        }
        
        int mid = (start + end) / 2;
        ListNode left = mergeHelper(lists, start, mid);
        ListNode right = mergeHelper(lists, mid + 1, end);
        return mergeTwoSortedLists(left, right);
    }
    
    private ListNode mergeTwoSortedLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1);
        ListNode res = dummy;
        
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                res.next = l1;
                res = res.next;
                l1 = l1.next;
            } else {
                res.next = l2;
                res = res.next;
                l2 = l2.next;
            }
        }
        
        if (l1 != null) {
            res.next = l1;
        } else {
            res.next = l2;
        }
        
        return dummy.next;
    }
    
    void print(ListNode list){
        while(list!=null){
            System.out.print("" + list.val + "->");
            list = list.next;
        }
        
        System.out.println("null");
    }
}

What to improve

  • null pointer check

  • the index part is not necessary because we can use ListNode.next to find the next one should added into pq

  • divide and conquer method is a way better solution than the PriorityQueue solution