23. 合并K个排序链表
题目描述
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
思路梳理1–分治法
采用分治法的思想,将 k 个排序链表先合并为 k/2 个链表。依次循环,直至合并为1个链表为止。
注意:从 k 到 k/2 时,如何定义索引,将每两个链表合并,而且必须符合奇数、偶数个链表的情况。
解决办法:
k = (n+1)/2; lists[i] = self.merge2Lists(lists[i], lists[i+k])
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
if lists == []:
return
n = len(lists)
while n>1:
# 采用分治法,将所有列表两两合并,将复杂度减半
k = (n+1)/2
for i in range(n/2):
lists[i] = self.merge2Lists(lists[i], lists[i+k])
n = k
return lists[0]
def merge2Lists(self, l1, l2):
head = ListNode(-1)
temp = head
# 如果两个链表都非空
while l1 and l2:
if l1.val < l2.val:
temp.next = l1
l1 = l1.next
else:
temp.next = l2
l2 = l2.next
temp = temp.next
if l1:
temp.next = l1
if l2:
temp.next = l2
return head.next
思路梳理2–最小堆
- 将每个链表中的首元素取出来,构建一个最小堆(加入最小堆中);
- 取出堆顶元素(自动更新为整个堆中最小的元素),把取出元素的下一个元素加入堆中;
- 对堆重新排序;(只需要对根节点即索引为 0 的位置进行最小堆化)
- 循环上述操作,直至堆中没有元素,此时 k 个链表也合并为一个链表,返回首节点即可。
问题:
- 如何将取出元素的下一个元素加入堆中,记录索引?
将取出的元素以链表节点的形式加入堆中,按照 .val属性排序,按照 .next属性读取下一个元素。 - 弹出堆顶元素
堆顶元素在索引为 0 的位置。heap.pop(0)
- 超出时间限制
将堆顶元素弹出之后,只需要对堆顶元素重新进行 堆最小化 的操作。min_heapify(heap, 0)
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
if lists == []:
return
n = len(lists)
if n<=1:
return lists[0]
min_heap = []
for list1 in lists:
if list1:
min_heap.append(list1)
head = ListNode(-1)
temp = head
self.build_min_heap(min_heap)
while min_heap:
# 弹出最小元素,在索引为 0 的位置
temp.next = min_heap[0]
temp = temp.next
if temp.next:
min_heap[0] = temp.next
else:
min_heap[0] = min_heap[-1]
min_heap.pop()
# 只需要对索引0进行堆最小化操作
self.min_heapify(min_heap,0)
return head.next
def min_heapify(self, heap,i):
n = len(heap)
# 左儿子
left = 2 * i+1
# 右儿子
right = 2 * i +2
# 取出三者中的最大值对应的索引
if left < n and heap[left].val < heap[i].val:
smallest = left
else:
smallest = i
if right < n and heap[right].val < heap[smallest].val:
smallest = right
if smallest != i:
heap[i], heap[smallest] = heap[smallest], heap[i]
self.min_heapify(heap,smallest)
def build_min_heap(self, nums):
size = len(nums)
# 输入异常情况
if nums is None or size<=0:
return
if size == 1:
return nums
for i in range(size // 2, -1, -1):
self.min_heapify(nums, i)