Merge k Sorted Lists
https://leetcode.com/problems/merge-k-sorted-lists
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
"""
k = num of lists
N = total number of nodes
"""
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
return self.mergeKListsDivideAnConquer(lists) # best solution
def mergeKListsDivideAnConquer(
self,
lists: List[Optional[ListNode]]
) -> Optional[ListNode]:
"""
Time: O(N*log_2(k)) -> iterates the N nodes log_2(k) times
Space: O(N) -> N stack calls
"""
filtered_list = list(filter(lambda item: item is not None, lists))
if len(filtered_list) == 0:
return None
return self.helper_mergeKListsDivideAnConquer(filtered_list)
def helper_mergeKListsDivideAnConquer(
self,
lists: List[Optional[ListNode]]
) -> Optional[ListNode]:
if len(lists) == 1:
return lists[0]
if len(lists) % 2 != 0: # if impair length
middle = int(len(lists) / 2) # find middle
return self.mergeTwoListsRecursive( # apply the merge twice
l1=self.mergeTwoListsRecursive( # for the two halfs
l1=self.helper_mergeKListsDivideAnConquer(lists[:middle]),
l2=self.helper_mergeKListsDivideAnConquer(lists[middle+1:])
),
l2=lists[middle] # and for the middle one
)
# find middle for pair list
middle = int(len(lists) / 2)
return self.mergeTwoListsRecursive(
l1=self.helper_mergeKListsDivideAnConquer(lists[:middle]),
l2=self.helper_mergeKListsDivideAnConquer(lists[middle:])
)
def mergeKListsTwoByTwo(
self,
lists: List[Optional[ListNode]]
) -> Optional[ListNode]:
"""
Time: O(N*k) -> iterates the N nodes for the k lists
Space: O(N) -> N stack calls
"""
if len(lists) == 0:
return None
ordered = ListNode(-float("inf"))
for l in lists:
if l is not None:
ordered = self.mergeTwoListsRecursive(l, ordered)
return ordered.next
def mergeTwoListsRecursive(
self,
l1: Optional[ListNode],
l2: Optional[ListNode]
) -> Optional[ListNode]:
"""
Time: O(N)
Space: O(1) from variables + O(N) from stack calls => O(N)
"""
merged = None
curr = None
if l1 is None:
return l2
elif l2 is None:
return l1
elif l1.val <= l2.val:
curr = l1
merged = self.mergeTwoListsRecursive(l1.next, l2)
else:
curr = l2
merged = self.mergeTwoListsRecursive(l1, l2.next)
curr.next = merged
return curr
def mergeKListsCompareOneByOne(
self,
lists: List[Optional[ListNode]]
) -> Optional[ListNode]:
"""
Time: O(N*k) -> find the smallest node for the k lists
until all N nodes are visited
Space: O(1) from variables + O(N) from stack calls => O(N)
"""
node, index = self.findMinNode(lists)
if node is None:
return None
merged = self.mergeKListsRecursive(
lists[:index] + [node.next] + lists[index+1:]
)
node.next = merged
return node
def findMinNode(
self,
lists: List[Optional[ListNode]]
) -> Tuple[ListNode, int]:
values = list(map(lambda node: node.val if node else None, lists))
not_none_values = list(filter(lambda item: item is not None, values))
if len(not_none_values) == 0:
return None, -1
min_value = min(not_none_values)
min_index = values.index(min_value)
return lists[min_index], min_index
Last updated