23. Merge k Sorted Lists
Hard
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
笔记:
1. 解法一 (暴力)
每次合并两个,然后用新合并的去跟第三个合并。
比如:合并a,b,c,d
先ab合并,将头节点赋值给a,然后ac合并,将头节点赋值给a,然后合并ad,将头节点赋值给a,最后返回a
LeeCode上面返回的运行时间如下:
class Solution:
def mergeKLists(self, lists):
if not lists:
return None
n = len(lists)
i = 1
while i < n:
lists[0] = self.merge_two_lists(lists[0], lists[i])
i += 1
return lists[0]
def merge_two_lists(self, list1, list2):
current_head = ListNode()
return_head = current_head
while list1 and list2:
if list1.val <= list2.val:
current_head.next = list1
current_head = current_head.next
list1 = list1.next
else:
current_head.next = list2
current_head = current_head.next
list2 = list2.next
current_head.next = list2 if not list1 else list1
return return_head.next
2. 分治 (divide and 从conquer)
将所有的链表分成两个部分,然后对应合并两个链表,比如 链表1,2,3,4,5,6. 先合并1-4,2-5,3-6,然后合并1-4-3-6,最后合并1-4-3-6-2-5。
LeeCode上面的运行时间为124ms,对面暴力的4612ms,速度明显提升很多。
class Solution:
def mergeKLists(self, lists):
if not list:
return None
n = len(lists)
while n > 1:
k = (n + 1) // 2
for i in range(n//2):
lists[i] = self.merge_two_lists(lists[i], lists[i + k])
n = k
return lists[0]
def merge_two_lists(self, list1, list2):
current_head = ListNode()
return_head = current_head
while list1 and list2:
if list1.val <= list2.val:
current_head.next = list1
current_head = current_head.next
list1 = list1.next
else:
current_head.next = list2
current_head = current_head.next
list2 = list2.next
current_head.next = list2 if not list1 else list1
return return_head.next
3. 利用最小堆
思路:创建一个空的节点head,方便找到合并后的头节点(head.next),然后创建tail_node变量指向head节点,此节点为当前合并链的尾结点。首先将每条链的头节点放入到创建的堆中,此时堆顶的节点就是当前值最小的节点。弹出堆顶的节点,将tail节点的next指向当前弹出的节点(cur_node), 并修改tail_node节点为cur_node。如果cur_node的next还有节点,将cur_node.next压入到堆中,如果cur_node.next为None,不做任何处理。接着继续弹出堆顶的节点,进行如上操作,知道堆为空,则合并完毕。最后合并完的链表的头节点则为head.next
python 中使用heapq 库中的函数来创建堆,相关函数如下:
需要注意的是,heapify(heap)中的heap必须是一个list. 在Python3 中,不能直接使用node节点作为 堆的元素,比如heappush(heap, (node.val, node)), 这样是会报错的。正确的用法是 heappush(heap, (node.val, index))。确保堆中的数据可以直接比较 。所以在下面的代码中使用了节点的索引,因为使用了索引,所以需要更新lists中对应索引的节点,也就是代码中的
lists[cur_node_index] = cur_node.next
运行时间:
class Solution:
def mergeKLists(self, lists):
if not lists:
return None
heap = []
for index, node in enumerate(lists):
if node:
heap.append((node.val, index))
heapq.heapify(heap)
head = ListNode()
tail_node = head
while heap:
cur_node_index = heapq.heappop(heap)[1]
cur_node = lists[cur_node_index]
if cur_node.next:
heapq.heappush(heap, (cur_node.next.val, cur_node_index))
lists[cur_node_index] = cur_node.next
tail_node.next = cur_node
tail_node = cur_node
return head.next