Merge k sorted lists - LeetCode (2023)

Problem definition

Alkesh Ghorpade

·

follow us

Published in

Geek for technology

·

10 minutes of reading

·

4 days ago

You get a seriesklinked listsarena, each linked list is sorted in ascending order.

Merge all linked lists into a sorted linked list and return it.

Statement of problem received from:https://leetcode.com/problems/merge-k-sorted-lists

Example 1:

Input: lister = [[1, 4, 5], [1, 3, 4], [2, 6]]
Output: [1, 1, 2, 3, 4, 4, 5, 6]
Explanation: The linked lists are:
[
1->4->5,
1->3->4,
2->6
]
combine them into a sorted list:
1->1->2->3->4->4->5->6

Example 2:

Input: lister = []
Exit: []

Example 3:

Input: lister = [[]]
Exit: []

Limitations:

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

Solutions to the k-merge problem with sorted lists

Method 1: Brute force

In one of our previous blog posts, we discussed how to do thisSort a linked list one by one. In this problem we need to merge a sorted K linked list.

A simple solution would be to combine all k linked lists into one list (in any order). Then use the merge sort algorithm described inSort the listPosition. The worst time complexity of this approach isO(n * log(n)), WhereNis the total number of nodes in all k lists. This approach is inefficient because we no longer use sorted lists.

Let's see the C++ snippet of this approach below:

ListNode* getLastNode(ListNode* main) {
ListNode* stream = main;
ListNode* next = current->next;

while(next != NULL) {
current = next;
next = current->next;
}

return flow;
}

// Combine k sorted lists: main function
ListNode* mergeKSortedLists(vector& blade) {
if(list.size() == 0) {
returner NULL;
}

// combine all k sorted linked lists into one list
for(int i = 0; i < list.size() - 1; i++) {
// get the last node
ListNode* last = getLastNode(lister[i]);

last->next = lists[i + 1];
}

// perform a merge sort on the list [0]
return sortList(list[0]);
}

// sort of merge two lists
ListNode* mergelist(ListNode *l1, ListNode *l2) {
ListNode *ptr = new ListNode(0);
ListNode *current = ptr;

while(l1 != NULL && l2 != NULL) {
if(l1->value <= l2->value) {
current->next = l1;
11 = 11->next;
} Ellers {
stream->next = l2;
l2 = l2->następny;
}

stream = stream->next;
}

if(l1 != NULL) {
current->next = l1;
11 = 11->next;
}

if(l2 != NULL) {
stream->next = l2;
l2 = l2->następny;
}

return ptr->next;
}

ListNode* sortList(ListNode* main) {
if(header == NULL || header->next == NULL)
back of head;

ListNode *temp = NULL;
ListNode *slow = main;
ListNode *fast = main;

// splits the list into two halves
while(quick != NULL && quick->next != NULL) {
temperature = slow;
slow = slow->next;
fast = fast->next->next;
}

temp->next = NULL;

// calls sortList recursively for two lists
ListNode* l1 = sortList(head);
ListNode* l2 = sortList(langsom);

// merge list l1 and l2
return merges(l1,l2);
}

The second brute force approach to solving the problem comes fromconcatenation of two sorted listsmoment. We combine the first two listsblade[0]zblade[1]and save the result. We combine the result with the third listblade[2]and repeat the process k - 1 times.

This method is relatively easy. But the time complexity of this approach isO(n * k)where n is the number of elements to be connected.

The C++ snippet of this approach is as follows:

// Combine k sorted lists: main function
ListNode* mergeKSortedLists(vector& blade) {
if(list.size() == 0) {
returner NULL;
}

return mergeKSortedListsHelper(list);
}

// Helper function to merge k sorted lists
ListNode* mergeKSortedListsHelper(vector& blade) {
int size = list.size();

// Subtract from penultimate list
for (int i = 1; i <= size; i++) {
mens (sand) {
ListNode head1 = blade[0], head2 = blade[i];

// if the list is complete
if(head1 == NULL) {
Holidays;
}

if(head1->val >= head2->val) {
lists[i] = header2->next;
main2->next = main1;
lists[0] = main2;
} Ellers {
// Loop through the first list
while (header1->next != NULL) {
// find exactly this node in the first list
// greater than the current node in the second list
if (head1->next->val >= head2->val) {
lists[i] = header2->next;
heading2->next = heading1->next;
main1->next = main2;
Holidays;
}

main1 = main1->next;
}

if(heading1->next == NULL) {
lists[i] = header2->next;
header2->next = NULL;
main1->next = main2;
header1->next->next = NULL;
Holidays;
}
}
}
}

return letters [0];
}

The time complexity of the above two approaches is very high because we are not using sorted lists. We can optimize the approach by using an additional data structure: Min Heap.

Method 2: Use the minimum stack

We can optimize the above approach with aMy bowl. The Min Heap root is always the smallest element.

According to the problem formulation, all linked lists are sorted. Therefore, the first item on the list will be the smallest. We add the first elements of all linked lists to the minimum heap. We extract the smallest element, the Min Heap root. After removing the root, we increment the index of the list that the root element belonged to. The next node in this list is added to the min heap. We keep removing the root and adding another node from the lists to the heap until all the lists have gone through and the heap is empty.

This algorithm can also be used to concatenate K sorted arrays. The time complexity of the algorithm isO(n * log(k)). Where n is the number of elements in all lists and k is the number of linked lists. The complexity of space iswell)where k is the minimum heap size.

Let's check the algorithm for this approach.

- priority queuecompare> currently

- for int i = 0; Ja- if lists[i] != NULL
- pq.push(table[i])
- if it's over
- At the end

- if pq.empty()
- returner NULL
- if it's over

- ListNode* result = ny ListNode(0)
ListNode* property = dump

- while loop!pq.empty()
- ListNode* current = pq.top()
pq.pop()

- last->next = current
last = last->next

- if current->next != NULL
pq.push(current->next)
- if it's over
- at the end

- return result->next

Let's check the algorithm in C++ code.

ListNode* mergeKSortedLists(vector& blade) {
priority queuecompare>pq;
int k = lists.size();

// Push the first nodes of all k lists into the 'pq' priority queue
για (int i = 0; i < k; i++)
if (liste[i] != NULL)
pq.push(list[i]);

if (pq.pusty())
returner NULL;

ListNode *result = new ListNode(0);
ListNode *last = result;

// Loop until 'pq' is not empty
while (!pq.pusty()) {
// Get the top "pq" element
ListNode* stream = pq.top();
pq.pop();

// Add the top 'pq' element to the result list
last->next = current;
last = last->next;

// If the current next node is not NULL, add it to the priority queue
if (current->next != NULL) {
pq.push(current->next);
}
}

// return the result
return results->next;
}

Method 3: Use divide and conquer

By using Min Heap we reduced the time complexity toO(n * log(k))but it is necessarywell)extra stack space. We can solve this problem in constant space by using the divide and conquer technique.

As mentioned in our Brute force approach, we know how to do itmerge two sorted lists. The idea is to pair k lists and connect each pair in linear time usingO(1)space. After the first iteration, k/2 lists of size 2 * n remain. After the second cycle, k/4 lists remain. We repeat this process until we are left with a list.

Let's check the algorithm first.

// mergeKLists(vectorand letters)
- if list.size() == 0
- returner NULL
- if it's over

- zwróć mergeKListsHelper(lister, lists.size() - 1)

// mergeKListsHelper(vector& listy, int last)
// Merge lists until there is one list left
- loop during last != 0
- initialize i = 0, j = last

- loop while i < i
// merge list i with list j
// store the merged result in list i
- lists[i] = mergeLists(lists[i], lists[j])

- increase i = i++
- reduce j = j--

- if i >= i
- last = me
- if it's over
- at the end
- at the end

- return letters[0]

// mergeLists(ListNode*l1, ListNode*l2)
- set ListNode* main = NULL

- if l1 == NULL
- retur l2
- else if l2 == NULL
- return l1
- if it's over

- if l1->value < l2->value
- setting header = l1
- set l1 = l1->next
-Other things
- setting header = l2
- set l2 = l2->next
- if it's over

- set ListNode* p = main

- loop under l1 && l2
- if l1->value < l2->value
- set p->next = l1
- set l1 = l1->next
-Other things
- set p->next = l2
- set l2 = l2->next
- if it's over

- set p = p->next
- at the end

- if l1 != NULL
- p->next = l1
-Other things
- p->next = l2
- if it's over

- return header

The time complexity of the above approach isO(n * log(k)), and the complexity of the space isO(1).

Let's see our solutionsC++,Golang, iJavaScript.

C++ solution

class solution {
public:
ListNode* mergeKLister(vector& blade) {
if(list.size() == 0) {
returner NULL;
}

return mergeKListsHelper(lists, lists.size() - 1);
}

ListNode* mergeKListsHelper(vector& listy, int last) {
// Merge lists until there is one list left
while (last != 0) {
int i = 0, j = last;

mens (i < j) {
// merge list i with list j
// store the merged result in list i
lister[i] = mergeLists(lister[i], lister[j]);

i++;
J--;

// last update after connecting all pairs
if(i >= j) {
last = j;
}
}
}

return letters [0];
}

ListNode* mergeLists(ListNode* l1, ListNode* l2) {
ListNode* head = NULL;

// if any of the lists are empty
// return the second list.
if(l1 == NULL) {
retur l2;
} andet if(l2 == NULL) {
return l1;
}

// select the header based on the smaller value of the two lists.
if(l1->value < l2->value){
main = 11;
11 = 11->next;
} Ellers {
main = l2;
l2 = l2->następny;
}

Listeknude *p;
p = head;

mens(l1 && l2){
if(l1->value < l2->value){
p->next = 11;
11 = 11->next;
} Ellers {
p->next = l2;
l2 = l2->następny;
}

p = p->next;
}

if(l1 != NULL){
p->next = 11;
} Ellers {
p->next = l2;
}

back of head;
}
};

Golang's solution

func mergeKLists(lister []*ListNode) *ListNode {
if len(sheet) == 0 {
return null;
}

returner mergeKListsHelper(lister, len(lister) - 1)
}

func mergeKListsHelper(listy []*ListNode, last int) *ListNode {
// Merge lists until there is one list left
at end != 0 {
i, j := 0, last

for (i < j) {
// merge list i with list j
// store the merged result in list i
lists[i] = mergeLists(lists[i], lists[j])

i++;
J--;

// last update after connecting all pairs
if i >= j {
last = me
}
}
}

return letters[0]
}

func mergeLists(l1, l2 *ListNode) *ListNode {
var head *ListNode
main = null

// if any of the lists are empty
// return the second list.
if l1 == zero {
retur l2
} else if l2 == null {
return l1
}

// select a header based on the smaller of the two lists.
if(l1.Value < l2.Value){
main = 11;
11 = 11. Next;
} Ellers {
main = l2;
l2 = l2.
}

p := head

for l1 != null && l2 != null {
αν l1.Val < l2.Val {
p.Next = l1
l1 = l1.Next
} Ellers {
p. Next = l2
l2 = l2. Derefter
}

p = p. Next
}

if l1 != zero {
p.Next = l1
} Ellers {
p. Next = l2
}

head turn
}

JavaScript solution

var mergeKLists = function(lister) {
if(list.length === 0) {
returner null;
}

return mergeKListsHelper(lists, lists.length - 1);
};

var mergeKListsHelper = function(lists, last) {
// Merge lists until there is one list left
while (last != 0) {
let i = 0, j = last;

mens (i < j) {
// merge list i with list j
// store the merged result in list i
lister[i] = mergeLists(lister[i], lister[j]);

i++;
J--;

// last update after connecting all pairs
if(i >= j) {
last = j;
}
}
}

return letters [0];
};

var mergeList = function (l1, l2) {
let head = null;

// if any of the lists are empty
// return the second list.
if(l1 == nul) {
retur l2;
} andet if(l2 == null) {
return l1;
}

// select a header based on the smaller of the two lists.
if(l1.value < l2.value){
main = 11;
11 = 11th next;
} Ellers {
main = l2;
l2 = l2. następny;
}

let p = head;

mens(l1 && l2){
if(l1.value < l2.value){
p.next = 11;
11 = 11th next;
} Ellers {
p next = l2;
l2 = l2. następny;
}

p = p.next;
}

if(l1!=pusty){
p.next = 11;
} Ellers {
p next = l2;
}

back of head;
};

Let's run our algorithm to see how the solution works.

Input: lister = [[1, 4, 5], [1, 3, 4], [2, 6]]

// MergeKList's function
Step 1: if list.size() == 0
3 == 0
FAKE WAR

Step 2: return mergeKListsHelper(lister, lists.size() - 1)
mergeKListsHelper(list, 2)

// mergeKListsHelper
Step 3: loop while last != 0
2 != 0
RIGHT

and = 0
j = last
= 2

loop mens i < i
0 < 2
RIGHT

lists[i] = mergeLists(lists[i], lists[j])
lists[0] = merge Lists(lists[0], lists[2])
= scalanie lists([1, 4, 5], [2, 6])

// MergeLists([1, 4, 5], [2, 6])
Step 4: This function will combine the list and return
[1, 2, 4, 5, 6]

// mergeKListsHelper
Trin 5: i++
and = 1

J--
j = 1

if i >= i
1 = 1
RIGHT

last = me
last = 1

loop mens i < i
1 < 1
FAKE WAR

// mergeKListsHelper
Step 6: loop while last != 0
1 != 0
RIGHT

and = 0
j = last
= 1

loop mens i < i
0 < 1
RIGHT

lists[i] = mergeLists(lists[i], lists[j])
lists[0] = merge Lists(lists[0], lists[1])
= scalanie lists([1, 2, 4, 5, 6], [1, 3, 4])

// MergeLists([1, 2, 4, 5, 6], [1, 3, 4])
Step 7: This function will combine the list and return
[1, 1, 2, 3, 4, 4, 5, 6]

// mergeKListsHelper
Trin 8: i++
and = 1

J--
j = 0

if i >= i
1 >= 0
RIGHT

last = me
last = 0

loop mens i < i
1 < 0
FAKE WAR

Step 9: loop during last != 0
0 != 0
FAKE WAR

Step 10: return lists[0]
[1, 1, 2, 3, 4, 4, 5, 6]

Originally published onhttps://alkeshghorpade.me.

Top Articles
Latest Posts
Article information

Author: Otha Schamberger

Last Updated: 14/04/2023

Views: 6109

Rating: 4.4 / 5 (55 voted)

Reviews: 86% of readers found this page helpful

Author information

Name: Otha Schamberger

Birthday: 1999-08-15

Address: Suite 490 606 Hammes Ferry, Carterhaven, IL 62290

Phone: +8557035444877

Job: Forward IT Agent

Hobby: Fishing, Flying, Jewelry making, Digital arts, Sand art, Parkour, tabletop games

Introduction: My name is Otha Schamberger, I am a vast, good, healthy, cheerful, energetic, gorgeous, magnificent person who loves writing and wants to share my knowledge and understanding with you.