You are given an array of k
linked-lists lists
, each linked-list is sorted in ascending order.
Merge all the linked-lists into one sorted linked-list and return it.
Example 1:
Input: lists = [[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 ] merging them into one sorted linked list: 1->1->2->3->4->4->5->6
Example 2:
Input: lists = [] Output: []
Example 3:
Input: lists = [[]] Output: []
Constraints:
k == lists.length
0 <= k <= 104
0 <= lists[i].length <= 500
-104 <= lists[i][j] <= 104
lists[i]
is sorted in ascending order.lists[i].length
will not exceed 104
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force way to combine many sorted lists into one big sorted list is simple, but not very efficient. We basically dump everything into one big pile, then sort the whole pile from scratch. This ensures the final result is correctly sorted, but involves a lot of extra work.
Here's how the algorithm would work step-by-step:
def merge_k_sorted_lists_brute_force(list_of_lists):
merged_list = []
# Combine all elements from all lists into a single list.
for sorted_list in list_of_lists:
merged_list.extend(sorted_list)
# Sort the combined list.
merged_list.sort()
return merged_list
We want to combine multiple sorted lists into one big sorted list as quickly as possible. The best way to do this is to use a 'divide and conquer' strategy, like organizing a tournament bracket. This approach breaks the big problem into smaller, easier-to-solve subproblems.
Here's how the algorithm would work step-by-step:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def merge_k_lists(list_of_linked_lists):
if not list_of_linked_lists:
return None
while len(list_of_linked_lists) > 1:
merged_lists = []
for i in range(0, len(list_of_linked_lists), 2):
list1 = list_of_linked_lists[i]
list2 = list_of_linked_lists[i + 1] if (i + 1) < len(list_of_linked_lists) else None
# Pair up the lists and merge them
merged_lists.append(merge_two_lists(list1, list2))
list_of_linked_lists = merged_lists
return list_of_linked_lists[0]
def merge_two_lists(list1, list2):
dummy_node = ListNode()
tail = dummy_node
# Iteratively pick the smaller node
while list1 and list2:
if list1.val < list2.val:
tail.next = list1
list1 = list1.next
else:
tail.next = list2
list2 = list2.next
tail = tail.next
# Append the remaining nodes, if any
if list1:
tail.next = list1
if list2:
tail.next = list2
return dummy_node.next
Case | How to Handle |
---|---|
Empty input list (lists is null or empty) | Return null immediately, as there are no lists to merge. |
Input list contains null or empty lists | Treat null or empty lists as if they don't exist, skipping them during the merge process. |
All input lists are empty | The merged list should be empty (return null) since all contributing lists are empty. |
Input list contains only one non-empty list | Return the single non-empty list directly, as it's already sorted. |
Lists contain duplicate values within themselves and across different lists | The solution should correctly handle duplicates, maintaining their order in the merged list. |
Lists contain a very large number of elements, approaching memory limits | Consider a divide-and-conquer approach or using an iterative merge to avoid stack overflow or excessive memory consumption. |
Lists contain extremely large or small integer values | Ensure integer overflow is handled appropriately, using `long` if necessary, depending on language constraints. |
One list is significantly longer than all others | The algorithm's performance should not degrade significantly; priority queue based solutions handle this gracefully. |