https://leetcode.com/problems/merge-k-sorted-lists/description/
Solution 1
You can copy the algorithm in Merge Two Sorted Linked Lists:
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: # pyright: ignore[reportRedeclaration]
lists: List[ListNode] = list(filter(lambda l: l is not None, lists)) # pyright: ignore[reportAssignmentType,reportDeprecated]
# INVARIANT: There is no empty list in `lists`
# INVARIANT: Each list in 'lists' is sorted
# CASE: 'lists' is empty or has 1 list
if len(lists) <= 1:
return None
# INVARIANT: 'lists' has at least 2 lists
head = lists[0]
for l in lists[1:]:
head = self.mergeSortedLists(head, l)
return head
def mergeSortedLists(self, l_head: Optional[ListNode], r_head: Optional[ListNode]) -> Optional[ListNode]:
if l_head is None:
return r_head
if r_head is None:
return l_head
# INVARIANT: l_head and r_head is not None
# INVARIANT: Each list is sorted
# NOTE: First, choose which node will be head of the merged list
if l_head.val < r_head.val:
head = l_head
l_head = l_head.next
else:
head = r_head
r_head = r_head.next
# NOTE: tail is tail of the merged list
tail = head
while l_head is not None and r_head is not None:
if l_head.val < r_head.val:
# NOTE: 'attach' left list to merged list
tail.next = l_head
# NOTE: Set new tail
tail = tail.next
# NOTE: 'pop' left list
l_head = l_head.next
else:
tail.next = r_head
tail = tail.next
r_head = r_head.next
# INVARIANT: left xor right is None
if l_head is not None:
tail.next = l_head
else:
tail.next = r_head
return head Solution 2
Rather than merging two lists at a time, you may merge all at once using a similar algorithm as Solution 1:
Solution 1 is generally faster than this solution
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: # pyright: ignore[reportRedeclaration]
lists: List[ListNode] = list(filter(lambda l: l is not None, lists)) # pyright: ignore[reportAssignmentType,reportDeprecated]
# INVARIANT: There is no empty list in `lists`
# INVARIANT: Each list in `lists` is sorted
# CASE: `lists` is empty or has 1 list
if len(lists) == 1:
return lists[0]
if len(lists) == 0:
return None
# INVARIANT: `lists` has at least 2 lists
# NOTE: Pick head that has the smallest value
head_idx = min(range(len(lists)), key=lambda i: lists[i].val)
tail = head = lists[head_idx]
if tail.next is not None:
lists[head_idx] = tail.next
else:
lists.pop(head_idx)
# NOTE: Keep beheading `lists` that has smallest value, and attach its head into tail of the new merged list
while len(lists) > 0:
# NOTE: Pick list that has the smallest head value
curr_idx = min(range(len(lists)), key=lambda i: lists[i].val)
tail.next = lists[curr_idx]
tail = tail.next
if tail.next is not None:
lists[curr_idx] = tail.next
else:
lists.pop(curr_idx)
return head