1.取值排序法
首先我们最先想到的可能是将所有链表的值放进一个数组中,然后进行排序,最后将排序后的元素依次构建新的链表。代码如下:
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
self.nodes = []
head = point = ListNode(0)
for l in lists:
while l:
self.nodes.append(l.val)
l = l.next
for x in sorted(self.nodes):
point.next = ListNode(x)
point = point.next
return head.next
假设N为所有节点的总数量,这种方法的时间复杂度是 O(Nlog N),空间复杂度是O(N)。
2.逐个比较法
这种方法是将每个链表依次从头开始比较,每次取k个链表中最小的,接在新的链表后,如下图所示:
由于获取每个排好序的节点时每个链表都要和k-1个链表比较一次,因此N个节点的时间复杂度是 O(kN),空间复杂度是O(N)。
3.优先队列法
优先队列可以根据元素值的大小来设置优先级,值最大/最小的拥有最高的优先级。这样,我们就可以快速地获取队列中最大/最小的元素。优先队列有两个核心方法:插入元素,删除最大元素,在python的PriorityQueue中可以分别使用put()和get()方法实现:
from Queue import PriorityQueue
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
head = point = ListNode(0)
q = PriorityQueue()
for l in lists:
if l:
q.put((l.val, l))
while not q.empty():
val, node = q.get()
point.next = ListNode(val)
point = point.next
node = node.next
if node:
q.put((node.val, node))
return head.next
对于N个节点每次比较进行O(logk) 的插入删除操作,因此总的时间复杂度是 O(Nlog k),空间复杂度是O(N)。
4.两两合并法
将k个链表的合并转化为两个链表合并问题。两个链表合并的方法如下:
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
l0 = ListNode(None)
l = l0
while l1 and l2:
if l1.val > l2.val:
l1, l2 = l2, l1
l.next = l1
l = l.next
l1 = l1.next
l1 = l1 or l2
l.next = l1
return l0.next
这种方法的时间复杂度是O(kN),空间复杂度是O(1).
5.分治法
如下图所示:
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
amount = len(lists)
interval = 1
while interval < amount:
for i in range(0, amount - interval, interval * 2):
lists[i] = self.merge2Lists(lists[i], lists[i + interval])
interval *= 2
return lists[0] if amount > 0 else lists
def merge2Lists(self, l1, l2):
head = point = ListNode(0)
while l1 and l2:
if l1.val <= l2.val:
point.next = l1
l1 = l1.next
else:
point.next = l2
l2 = l1
l1 = point.next.next
point = point.next
if not l1:
point.next=l2
else:
point.next=l1
return head.next
可以看出,这种方法对于每一个节点需要重复log(k)次,因此共需要Nlog(k)时间复杂度,空间复杂度只需要常数级。