Leetcode 23 Merge k Sorted Lists
题目描述
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路解析
- 思路一暴力法:将k个链表逐一两两合并,得到结果,代码如下:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
k = len(lists)
if k == 0:
return None
if k == 1:
return lists[0]
result = self.mergeTwoLists(lists[0], lists[1])
for i in range(2, k):
result = self.mergeTwoLists(result, lists[i])
return result
def mergeTwoLists(self, l1, l2):
if l1 is None:
return l2
if l2 is None:
return l1
result = ListNode(0) # 哑结点
result_temp = result
while l1 and l2:
if l1.val <= l2.val:
result_temp.next = ListNode(l1.val)
result_temp = result_temp.next
l1 = l1.next
else:
result_temp.next = ListNode(l2.val)
result_temp = result_temp.next
l2 = l2.next
if l1 is None:
result_temp.next = l2
else:
result_temp.next = l1
return result.next
但这样做,需要遍历整个列表以及列表中每一个链表的结点,时间复杂度为 O ( l e n ( l i s t s ) ∗ N ) , N 为 结 点 数 之 和 O(len(lists) * N),N为结点数之和 O(len(lists)∗N),N为结点数之和,不算为一种好的算法
- 思路二,也是暴力的思路,将所有结点的值存在一个列表里,对列表进行排序,最后生成一个排好序的链表,代码如下:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
nodes = []
for item in lists:
while item:
nodes.append(item.val)
item = item.next
nodes.sort()
result = ListNode(0)
result_temp = result
for node in nodes:
result.next = ListNode(node)
result = result.next
return result_temp.next
遍历所有结点的时间复杂度为 O ( N ) O(N) O(N),排序的时间复杂度为 O ( N ∗ l o g N ) O(N*logN) O(N∗logN),所以算法的整体时间复杂度为 O ( N ∗ l o g N ) O(N*logN) O(N∗logN).(python中sort()函数使用的是Timsort算法,平均时间复杂度为 O ( N ∗ l o g N ) O(N*logN) O(N∗logN))
这种思路也可以利用优先队列来实现排序这个操作,得到相同的结果。‘
- 思路三,分治
分治的算法其实和思路一有些相似,不同的是分治法是两两合并,最后归结为两个长度相差不大的链表合并得到结果。而思路一是逐一两两合并,实现过程并不相同。
注意分治的三条原则:
- 原问题可以分解为独立的子问题
- 当问题规模小到一定程度,问题可以直接求解
- 子问题解的合并即原问题的解
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
k = len(lists)
if k == 0:
return None
interval = 1
while interval < k:
for i in range(0, k - interval, interval * 2):
lists[i] = self.mergeTwoLists(lists[i], lists[i + interval])
interval *= 2
return lists[0]
def mergeTwoLists(self, l1, l2):
if not l1:
return l2
if not l2:
return l1
result = ListNode(0)
result_temp = result
while l1 and l2:
if l1.val <= l2.val:
result_temp.next = ListNode(l1.val)
result_temp = result_temp.next
l1 = l1.next
else:
result_temp.next = ListNode(l2.val)
result_temp = result_temp.next
l2 = l2.next
if not l1:
result_temp.next = l2
else:
result_temp.next = l1
return result.next
这段代码的关键在于两两合并出的代码,比较巧妙。
整体时间复杂度为 O ( N ∗ l o g 2 k ) O(N*log_2k) O(N∗log2k)