AfterAcademy Tech
•
10 Feb 2020

Asked in: Amazon, Google, Microsoft
Difficulty: Hard
Problem Description: Merge k sorted linked lists and return it as one sorted list.
Example :

You have to return the head of the first node after merging k lists. The node structure passed to your function will be
class ListNode
{
int val
ListNode next
}
Hint → Let's keep a pointer for every linked list. At any instant, you will need to know the minimum of elements at all pointer. Following it you will need to advance that pointer. Can you do this in complexity better than O(K)?
We will be discussing five different approaches to solve the problem:
The idea is to insert all the node values from all the k lists into an array. Sorting the array and creating a new linked list from the sorted array will give the required output.
Solution Steps
Pseudo Code
ListNode mergeKLists(ListNode[] lists, int k)
{
// x array to store all the values from lists
int x[]
for(i = 0 to k)
{
ListNode temp = lists[i]
while(temp is not null)
{
// append the value of temp to x
x.add(temp.val)
temp = temp.next
}
}
// sort all the values of x
sort(x)
// Head node to return
ListNode head(-1)
ListNode temp = head
for(i = 0 to x.size()) {
ListNode newVal(x[i])
temp.next = newVal
temp = temp.next
}
return head.next
}
Complexity Analysis
Time complexity: O(NlogN) where N is the total number of nodes. Collecting all the values costs O(N) time.
Space complexity: O(N). Creating a new linked list costs O(N) space.
Critical Ideas to Think
All the given lists are sorted, which means that the head of each list would be the smallest element in its chain. So we could extract the minimum from the k head nodes and append it to the result list.
Solution Steps
Pseudo Code
ListNode mergeKLists(ListNode[] lists, int k) {
int min_index = 0
ListNode head(0)
// reference pointer pointing to head
ListNode ref = head
while (true) {
bool isBreak = true
int min = INT_MAX
for (i = 0 to k) {
if (lists[i] is not null) {
if (lists[i].val < min) {
min_index = i
min = lists[i].val
}
isBreak = false
}
}
if (isBreak) {
break
}
ListNode a(lists[min_index].val)
ref.next = a
ref = ref.next
lists[min_index] = lists[min_index].next
}
ref.next = NULL
return head.next
}
Complexity Analysis
Time complexity: O(kN) where k is the number of linked lists.Almost every selection of nodes in final linked costs O(k) (k-1 times comparison).
Space complexity: O(n) Creating a new linked list costs O(n) space.
Critical Ideas to Think
Pseudo Code
ListNode mergeKLists(ListNode[] lists, int k) {
int min_index = 0
ListNode head(0)
// reference pointer to head
ListNode ref = head
while (true) {
bool isBreak = true
int min = INT_MAX
for (int i = 0 to k) {
if (lists[i] is not null) {
if (lists[i].val < min) {
min_index = i
min = lists[i].val
}
isBreak = false
}
}
if (isBreak) {
break
}
ref.next = lists[min_index]
ref = ref.next
lists[min_index] = lists[min_index].next
}
ref.next = null
return head.next
}
Complexity Analysis
Time complexity: O(kN) where k is the number of linked lists.Almost every selection of nodes in final linked costs O(k) (k-1 times comparison).
Space complexity: O(1) (Why?)
Critical Ideas to Think
Solution Steps
4. Return the resultant list.
Pseudo Code
int cmp(ListNode node1, ListNode node2) {
return node1.val - node2.val
}
ListNode mergeKLists(ListNode[] lists, int k) {
// priority Queue Q of type ListNode and comparator cmp
PriorityQueue Q(cmp)
for(int i = 0 to k){
if(lists[i] is not null){
Q.add(lists[i])
}
}
ListNode head(0)
ListNode ref = head
while(Q is not empty){
// fetch first element of queue
ref.next = q.poll()
ref = ref.next
ListNode next = ref.next
if(next is not null){
q.add(next)
}
}
return head.next
}
Complexity Analysis
Time complexity: O(Nlogk) (How?) where k is the number of linked lists.
Space complexity: O(n) Creating a new linked list costs O(n) space.
Priority queue (often implemented with heaps) costs O(k) space.
Critical Ideas to Think
Convert merge k lists problem to merge 2 lists (k-1) times.
You may refer to this merge 2 lists problem page for an explanation of the approach.
Following the concept of merging two lists, we can merge all the k lists taking two lists at a time.
Pseudo Code
ListNode mergeTwoSortedLists(ListNode A, ListNode B)
{
if(A == NULL)
return B
if(B == NULL)
return A
ListNode output = NULL
if(A.val < B.val)
{
output = A
A = A.next
}
else
{
output = B
B = B.next
}
ListNode curr = output
while(A != NULL && B!= NULL)
{
if(A.val > B.val)
{
curr.next = B
B = B.next
}
else
{
curr.next = A
A = A.next
}
curr = curr.next
}
if(A!= NULL)
curr.next = A
if(B!= NULL)
curr.next = B
return output
}
ListNode mergeKLists(ListNode[] lists, int k) {
if(k==1){
return lists[0];
}
if(k==0){
return null;
}
ListNode head = mergeTwoSortedLists(lists[0],lists[1])
for (int i = 2 to k) {
head = mergeTwoSortedLists(head,lists[i])
}
return head
}
Complexity Analysis
Time complexity: O(kN)(How?) where k is the number of linked lists.
We can merge two sorted linked lists in O(n) time where n is the total number of nodes in two lists.

Space Complexity: O(1). We can merge two sorted linked list in O(1) space.
Critical Ideas to Think
We don’t need to traverse most nodes many times repeatedly.
Thus, we’ll traverse almost N nodes per pairing and merging, and repeat this procedure about logk times.

Pseudo Code
ListNode mergeTwoSortedLists(ListNode A, ListNode B)
{
if(A == NULL)
return B
if(B == NULL)
return A
ListNode output = NULL
if(A.val < B.val)
{
output = A
A = A.next
}
else
{
output = B
B = B.next
}
ListNode curr = output
while(A != NULL && B!= NULL)
{
if(A.val > B.val)
{
curr.next = B
B = B.next
}
else
{
curr.next = A
A = A.next
}
curr = curr.next
}
if(A!= NULL)
curr.next = A
if(B!= NULL)
curr.next = B
return output
}
ListNode mergeKLists(ListNode[] lists, int k) {
if(k == 0){
return null
}
int interval = 1
while(interval < k){
int i = 0
while(i + interval < k) {
lists[i]= mergeTwoSortedLists(lists[i], lists[i+interval])
i = i + interval * 2
}
interval *= 2
}
return lists[0]
}
Complexity Analysis
Time complexity: O(Nlogk)(How?) where k is the number of linked lists.
We can merge two sorted linked lists in O(n) time where n is the total number of nodes in two lists.
Sum up the merge process and we can get →

Space complexity: O(1)
Critical Ideas to think

If you have any more approaches or you find an error/bug in the above solutions, please comment down below.
Happy Coding! Enjoy Algorithms!
AfterAcademy Tech
Sort a linked list using Merge Sort. This is a very famous interview problem that demonstrates the concept of recursion. This problem is quite similar to Merge Sort in Arrays.

AfterAcademy Tech
Merge two sorted linked lists and return it as a new sorted list. The new list should be made by splicing together the nodes of the first two lists.

AfterAcademy Tech
Merge sort is a divide-and-conquer algorithm based on the idea of breaking down a list into several sub-lists until each sublist consists of a single element and merging those sublists in a manner that results into a sorted list.

AfterAcademy Tech
Sort a linked list using insertion sort and return its head.
