You are given an array of k
linked-lists lists
, each linked-list is sorted in ascending order.
Merge all the linked-lists into one sorted linked-list and return it.
Example 1:
Input: lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
Explanation: The linked-lists are:
[
1->4->5,
1->3->4,
2->6
]
merging them into one sorted list:
1->1->2->3->4->4->5->6
Example 2:
Input: lists = []
Output: []
Example 3:
Input: lists = [[]]
Output: []
Constraints:
k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i]
is sorted in ascending order.- The sum of
lists[i].length
won't exceed10^4
从题目中可以看出k是每个列表的长度,然后设n为列表的个数。
暴力的解法就是从头开始,将前两个列表lists[0], lists[1]合并为一个新列表ANS,然后每次都拿ANS与之后的一个列表合并,直到将所有的lists[i]合并完成。
因为第一次归并要遍历k个元素,第二次是2k,然后3k, 4k 直到n-1k。这样的复杂度是,所以当n很大时容易超时(我试了一下,里面有个丧心病狂的k为1,然后n为10000的样例,妥妥的超时)。
所以为了避免多次重复的访问,我们需要同时合并所有的列表lists[i]。那么这样面对的问题就是怎么快速的比较n个list中哪个的首元素值最小。每次都遍历一次的话。因为每放入一个元素需要n次比较,而共有nk个元素。时间复杂度会还是。所以我们要减少比较的复杂度。
很明显能实现这一要求的数据结构就是小根堆了。对于n个元素来说,小根堆能一直实现复杂度为log(n)的插入,和O(1)的取出最小值。综合来讲时间复杂度应该为O(nklog(n))。long(n)的原因是因为我们堆里只放每个list中的头元素,所以最多会有n个元素。
具体的解题思路是:
一开始将n的列表的第一个元素放入小根堆,然后从其中取出最小的那一个节点E,将E放到答案列表的最后面,若E的next不为空,则将E的next放入到小根堆里。直到堆为空。
然而奇怪的是,当我用另一种解法,就是先将所有lists里的值都取出来,放入一个列表中,然后对其排序,再根据这个生成一个新的链表作为答案。这样的复杂度O(nklog(nk))。是慢于上面的小根堆解法的。可是实际结果是 这个远快于上面的小根堆。
我感觉应该是数据量太小,而小根堆的维护操作次数过多导致在小数据量的情况下,实际操作数解法二是远小于小根堆解法一的。(如果我理解错了,请指正一下)
代码:
解法一:小根堆
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class myHeap:
def __init__(self):
self.heap = [0] * 10010
self.index = 0
def push(self, n):
p = self.index
self.index += 1
self.heap[p] = n
while p > 0:
parent = int((p - 1) / 2)
if self.heap[parent].val > self.heap[p].val:
t = self.heap[parent]
self.heap[parent] = self.heap[p]
self.heap[p] = t
p = parent
else:
break
def pop(self):
if self.index < 0:
return None
topVal = self.heap[0]
self.index -= 1
self.heap[0] = self.heap[self.index]
p = 0
l = p * 2 + 1
r = p * 2 + 2
while l < self.index:
if r < self.index and self.heap[r].val < self.heap[l].val:
l = r
if self.heap[p].val > self.heap[l].val:
t = self.heap[p]
self.heap[p] = self.heap[l]
self.heap[l] = t
p = l
l = p * 2 + 1
r = p * 2 + 2
else:
break
return topVal
def size(self):
return self.index
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
h = myHeap()
for i in lists:
if not i == None:
h.push(i)
ans = ListNode()
p = ans
while h.size() > 0:
t = h.pop()
if not t.next == None:
h.push(t.next)
p.next = t
p = t
p.next = None
return ans.next
解法二:直接排序
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
nums = []
for i in lists:
p = i
while not p == None:
nums.append(p.val)
p = p.next
nums.sort()
head = ListNode()
p = head
for i in nums:
p.next = ListNode()
p = p.next
p.val = i
return head.next