力扣刷题(python)50天——第十三天:合并K个排序链表
题目描述
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
方法
这道题是上一题的拓展,拿到这题后我没考虑时间复杂度,想法和上一道题一样,依次比较N个节点然后迭代
解答
# 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
"""
lists = list(filter(None, lists))
l=len(lists)
if l:
pass
else:
return None
flag=lists[0].val
l=len(lists)
rec=0
for i in range(l):
if lists[i].val<flag:
rec=i
flag=lists[i].val
l1=lists[rec]
l2=l1
lists[rec]=lists[rec].next
while 1:
lists = list(filter(None, lists))
l=len(lists)
if lists:
min_v=float('inf')
for i in range(l):
if lists[i].val<min_v:
min_v=lists[i].val
rec=i
l1.next=lists[rec]
lists[rec]=lists[rec].next
l1=l1.next
else:
break
return l2
值得注意的是对于python,如果想去除列表中所有的None,最好用filter方法,或者用另一个空列表进行检测添加。
执行结果
执行结果:通过
执行用时 :6548 ms, 在所有 Python 提交中击败了5.01%的用户
内存消耗 :17.3 MB, 在所有 Python 提交中击败了55.61%的用户
.。。。。。。。这成绩意料之中,因为之前用
for i in range(l):
for each in lists:
if each is None:
lists.remove(each)
来去除None,耗费大量时间
所以一直超时,但也说明算法本身也有问题
在未改良的基础上,N个节点一共需要N个循环确定,每次循环都要遍历K个链表,并进行迭代操作,所以时间复杂度为O(NK),非常高。
参考改进:
1.使用暴力法
将所有链表进行一次遍历,放在数组中进行排序:
暴力法都比我强!!!!!!!!!!!!!!!QQA
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
作者:LeetCode
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/he-bing-kge-pai-xu-lian-biao-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
时间复杂度:O(N\log N) ,其中 N 是节点的总数目。
遍历所有的值需花费 O(N) 的时间。
一个稳定的排序算法花费 O(N\log N) 的时间。
遍历同时创建新的有序链表花费 O(N) 的时间。
2.分治:
将k个链表逐个两两配对为一组
该过程会有logk次,每次遍历N个节点,时间复杂度O(N log K)
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
作者:LeetCode
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/solution/he-bing-kge-pai-xu-lian-biao-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
心得:
不是搞得特别通时间复杂度是怎么算的,总感觉很别扭。对于为什么分治会时间上短那么多,我的理解是分治后会相当于进行一次排序,就简化了一些,也不是很懂。
摘自百度百科:
采用分治法解决的问题一般具有的特征如下:
- 问题的规模缩小到一定的规模就可以较容易地解决。
- 问题可以分解为若干个规模较小的模式相同的子问题,即该问题具有最优子结构性质。
- 合并问题分解出的子问题的解可以得到问题的解。
- 问题所分解出的各个子问题之间是独立的,即子问题之间不存在公共的子问题。
看了后现在觉得,既然上一题是两个链表合并,那么这道题不就能分治成很多两个链表合并的子问题了吗。加深了理解什么是分治。