题目描述
合并k个排序链表,并且返回合并后的排序链表。尝试分析和描述其复杂度。
输入参数
class Solution:
"""
@param lists: a list of ListNode
@return: The head of one sorted list.
"""
def mergeKLists(self, lists):
测试样例
样例 1:
输入: [2->4->null,null,-1->null]
输出: -1->2->4->null
样例 2:
输入: [2->6->null,5->null,7->null]
输出: 2->5->6->7->null
解题思路
首先说明下,输入参数lists中是每个链表的头部,它们都是一个ListNode()对象。
1、堆
利用堆实现起来很方便,思路也很直接明了。
先设置一个dummy作为一个空节点,dummy.next将会是最终返回序列的head。同时,设置一个tail节点,初始化为dummy,用于在排序过程中将所有node链接起来。
将lists中的每个head都拿出来加入堆中(注意要判断下这个head是否为null),这样它们就会按照值由大到小进行排序。
接着,依次弹出堆中的node,直至所有node都被弹出。每弹出一个node,就将tail.next链到这个node,然后将这个node赋给tail。若当前node.next不为null,那么将node.next加入堆中。这个过程会令tail一直保持为堆中值最小的node。
最后返回dummy.next即为整个序列中值最小的head。
注意了,ListNode类型本身并没有定义比较大小的方法,因此不能直接加入堆,这里有两种方法:
i). 自定义 ListNode.__lt__ == lambda node1, node2: node1 < node2;
ii). 将(node.val, index, node)三元组加入堆中,之所以要加上index是因为可能存在值相同的node
2、自顶向下的分冶归并
这种方法的思想是将当前待排序的范围分冶成一个个已排序好的小范围,获得已排序好的各个小范围后,再将它们相互进行排序归并。
3、自底向上的两两归并
与第2种方法的归并顺序相反,该方法的思想是不断对序列中的元素进行两两归并,直至序列归并为一个元素。
代码
1、堆
自定义__lt__的方式:
"""
Definition of ListNode
class ListNode(object):
def __init__(self, val, next=None):
self.val = val
self.next = next
"""
# 重载less than用于比较ListNode的值大小
ListNode.__lt__ = lambda node1, node2: node1.val < node2.val
import heapq
class Solution:
"""
@param lists: a list of ListNode
@return: The head of one sorted list.
"""
def mergeKLists(self, lists):
# write your code here
heap = []
for node in lists:
# 注意要判断下node是否为null
if node:
heapq.heappush(heap, node)
dummy = ListNode(None)
tail = dummy
while heap:
# tail每次都变为heap中值最小的node
head = heapq.heappop(heap)
tail.next = head
tail = tail.next
if head.next:
heapq.heappush(heap, head.next)
return dummy.next
将元组加入堆的方式:
i).
import heapq
class Solution:
"""
@param lists: a list of ListNode
@return: The head of one sorted list.
"""
def mergeKLists(self, lists):
# write your code here
heap = []
for index, node in enumerate(lists):
# 注意要判断下node是否为null
if node:
# 将node.val加入heap用于排序
# 因为本身ListNode没有定义比较大小的方法
# 并且由于因为有值相同的node,因此还要加入索引用于排序比较
heapq.heappush(heap, (node.val, index, node))
dummy = ListNode(None)
tail = dummy
while heap:
# tail每次都变为heap中值最小的node
_, index, head = heapq.heappop(heap)
tail.next = head
tail = tail.next
if head.next:
heapq.heappush(heap, (head.next.val, index, head.next))
return dummy.next
ii).
import heapq
class Solution:
"""
@param lists: a list of ListNode
@return: The head of one sorted list.
"""
def mergeKLists(self, lists):
# write your code here
heap = []
for node in lists:
# 注意要判断下node是否为null
while node:
heapq.heappush(heap, node.val)
node = node.next
dummy = ListNode(None)
tail = dummy
while heap:
# heap弹出的是节点的值,需要重新构造ListNode
head = ListNode(heapq.heappop(heap))
tail.next = head
tail = tail.next
return dummy.next
2、自顶向下的分冶归并
class Solution:
"""
@param lists: a list of ListNode
@return: The head of one sorted list.
"""
def mergeKLists(self, lists):
return self.merge_range_lists(lists, 0, len(lists) - 1)
def merge_range_lists(self, lists, start, end):
if start == end:
return lists[start]
# 分冶
mid = (start + end) // 2
left = self.merge_range_lists(lists, start, mid)
right = self.merge_range_lists(lists, mid + 1, end)
return self.merge_two_lists(left, right)
def merge_two_lists(self, head1, head2):
tail = dummy = ListNode(None)
# tail始终为head1和head2的较小者
while head1 and head2:
if head1.val < head2.val:
tail.next = head1
head1 = head1.next
else:
tail.next = head2
head2 = head2.next
tail= tail.next
# 注意head1或head2可能还存在
if head1:
tail.next = head1
if head2:
tail.next = head2
return dummy.next
3、自底向上的两两归并
class Solution:
"""
@param lists: a list of ListNode
@return: The head of one sorted list.
"""
def mergeKLists(self, lists):
# 自底向上将lists中的head两两归并
# 直至lists中归并为一个head
while len(lists) > 1:
merged_lists = []
for i in range(0, len(lists), 2):
if i + 1 < len(lists):
merged_head = self.merge_two_lists(lists[i], lists[i +1])
else:
merged_head = lists[i]
merged_lists.append(merged_head)
lists = merged_lists
return lists.pop()
def merge_two_lists(self, head1, head2):
tail = dummy = ListNode(None)
# tail始终为head1和head2的较小者
while head1 and head2:
if head1.val < head2.val:
tail.next = head1
head1 = head1.next
else:
tail.next = head2
head2 = head2.next
tail= tail.next
# 注意head1或head2可能还存在
if head1:
tail.next = head1
if head2:
tail.next = head2
return dummy.next