给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
解法一
自己看答案前的做法,主要思想:和合并两个有序链表一样,每次比较k个链表的节点值大小,并记录下来,将比较的那个链表指向next。
代码如下,附详细注释
def mergeKLists1(lists):
# 特殊情况判断
if not lists: return None
dummy = ListNode() # 哑节点
pre = dummy
isGoon = True # 标记是否还需要进行一次大的循环
while isGoon:
isGoon = False # 默认每次进来都为False
isFirst = True # 记录是否是第一个节点
index = -1
for i in range(len(lists)): # 遍历整个链表数组
ln = lists[i]
if ln is not None:
isGoon = True # 如果有节点不为None, 那么就设置为True,继续进行大循环
if isFirst: # 链表不为None时,记录第一个节点和该链表位于数组中的位置
temp = ln
index = i
isFirst = False
else:
if ln.val < temp.val: # 如果后面有节点比前面节点的值小,就记录下来
temp = ln
index = i
if index >= 0: # 如果记录的有节点
pre.next = temp # 就将上面比较下来的最小节点作为pre的下一个节点
pre = pre.next # 并将pre指针指向下一个节点
lists[index] = lists[index].next # 将刚刚使用的数组中的链表指向它的下一个节点,用于后面的比较
# 如果数组中有个链表为None了,就移除数组,减少后面的遍历
if lists[index] is None:
del lists[index]
return dummy.next # 返回哑节点的下面节点,就是所求结果
解法二
队列 参考力扣官方答案
主要思想:维护当前每个链表没有被合并的元素的最前面一个,k 个链表就最多有 k 个满足这样条件的元素,每次在这些元素里面选取 val 属性最小的元素合并到答案中。在选取最小元素的时候,我们可以用优先队列来优化这个过程。
Python2的写法:
from Queue import PriorityQueue
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
head = point = ListNode() # 声明头结点和构建链表的节点
q = PriorityQueue() # 声明一个优先级队列
for l in lists:
if l:
q.put((l.val, l)) # 将 第一个节点和队列作为一个元祖,也就是item放入优先队列当中
# 循环迭代队列,直到队列为空
while not q.empty():
val, note = q.get() # 这里每次取出的节点和队列,就是val值最小的节点对应的那个item
point.next = ListNode(val) # 将节点值放入最终有序链表中
point = point.next # 将指针指向下一个节点
note = note.next # 将取出的这个链表的指针也指向下一个节点
if note:
q.put((note.val, note)) # 如果节点不为空,再继续放入队列中
return head.next
Python3的写法:
# 导入优先级队列
from queue import PriorityQueue
def mergeKLists2(lists):
"""使用队列求解"""
head = point = ListNode() # 声明头结点和构建链表的节点
q = PriorityQueue() # 声明一个优先级队列
for index, l in enumerate(lists):
if l:
# python 优先队列 PriorityQueue,python3 不允许插入优先级相同的值或者是无法判断优先级的值到优先队列。
q.put((l.val, index, l)) # 将 第一个节点和队列作为一个元祖,也就是item放入优先队列当中
# 循环迭代队列,直到队列为空
while not q.empty():
val, index, note = q.get() # 这里每次取出的节点和队列,就是val值最小的节点对应的那个item
point.next = ListNode(val) # 将节点值放入最终有序链表中
point = point.next # 将指针指向下一个节点
note = note.next # 将取出的这个链表的指针也指向下一个节点
if note:
q.put((note.val, index, note)) # 如果节点不为空,再继续放入队列中
return head.next
解法三
分治 参考力扣官方答案
主要思想:先将数组中的链表两两合并,然后再将合并的链表,继续两两合并,最后剩下的那个链表就是所求的链表。这里使用求两个有序链表合并的方法。
def mergeKLists3(lists):
"""分治"""
def merge2Lists(l1, l2):
"""合并两个有序链表"""
head = point = ListNode()
while l1 and l2:
if l1.val <= l2.val:
point.next = l1
l1 = l1.next
else:
point.next = l2
l2 = l2.next
point = point.next
point.next = l1 if l1 is not None else l2
return head.next
amount = len(lists) # 记录输入列表的个数
interval = 1 # 记录初始间隔为 1
while interval < amount: # 通过while循环将输入队列两两合并
for i in range(0, amount - interval, interval * 2):
lists[i] = merge2Lists(lists[i], lists[i + interval]) # 合并两个链表
interval *= 2 # 间隔数乘以2
return lists[0] if amount > 0 else None # 最后剩下的第一个链表,就是所求链表