leetcode23. 问题描述
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
![](https://i-blog.csdnimg.cn/blog_migrate/6e43e98aea266a63476328c81c8fe4a4.png)
解题思路:1.暴力循环求解,不知道为啥不管碰到啥题,能用暴力解决的我绝不多想,可能我思想比较暴力?不多说,先感受一下暴力的快感吧。
想法很简单,K个有序链表,先把1号链表和2号链表合并得到一个新的有序链表,把新链表和3号链表合并得到新链表,然后继续循环,把K个链表循环完最后的链表就是合并后的链表。用一句话来说,用一个新的空链表来遍合并K个链表,将上一次得到的新链表加入下次合并中。
其中,一直要用的函数就是两个有序链表的合并函数,基本思路如下:判断两个链表的头结点,选择值最小的作为新的头结点,如果相同选择第一个作为新头结点,然后用current1和current2指针,分别指向还没有加入到新链表的剩余有序链表。并用一个end指针来维护新链表的数组尾部,判断current1和current2值大小,不断加入到新链表中来。下图表示其中一个状态向另外一个状态的过度
![](https://i-blog.csdnimg.cn/blog_migrate/0e8c877b9436bebe955b7ac7541d301a.png)
直到某个链表循环结束,我们用end指向将另外一个剩下的current,返回new_head节点就可以。整体代码如下,merge2Lists函数表示合并两个有序链表。
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
if not lists:
return []
#循环k个链表过程
head = lists[0]
for i in range(1,len(lists)):
head = self.merge2Lists(head, lists[i])
return head
#合并两个有序链表
def merge2Lists(self, head1, head2):
if not head1:
return head2
if not head2:
return head1
current1 = head1
current2 = head2
if current2.val>=current1.val:
new_head = head1
end = head1
current1 = current1.next
else:
new_head = head2
end = head2
current2 = current2.next
while current1 and current2:
if current2.val>=current1.val:
end.next = current1
end = current1
current1 = current1.next
else:
end.next = current2
end = current2
current2 = current2.next
if current1:
end.next = current1
if current2:
end.next = current2
return new_head
另外需要对k=0判断,还有空链表等边界值判断,反正我每次都是调试才记得加。可能leetcode这题的设置时间复杂度设置的要求不高,暴力解法居然过了
不过时间复杂度可能感人,突然感觉这个题的难点好像是在时间复杂度分析呀,然后来分析一波吧。假设k个n长度的两个链表的合并时间复杂度为O(2n),然后再加一个就是k(3n),k个就是(kn),总的时间复杂度为
O
(
2
n
+
3
n
+
4
n
+
.
.
.
k
n
)
=
O
(
k
2
n
/
2
)
=
O
(
k
2
n
)
O(2n+3n+4n+...kn) = O(k^2n/2)=O(k^2n)
O(2n+3n+4n+...kn)=O(k2n/2)=O(k2n)
2.分治归并求解:不满大家说,虽然我很菜,想到暴力方法的同时,我就想到用分支归并的方法,因为这个和归并排序实在是太像了,前几天的刚写完归并排序。感兴趣可移步leetcode51. 数组中的逆序对
用以上的两个有序链表的合并函数,代替归并中的merge即可。同样,这里建议熟悉归并后再看代码吧。
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
if len(lists)==0:
return []
l = 0
r = len(lists)-1
if l>=r:
return lists[0]
else:
mid = (l+r)//2
head1 = self.mergeKLists(lists[:mid+1])
head2 = self.mergeKLists(lists[mid+1:])
return self.merge2Lists(head1,head2)
def merge2Lists(self, head1, head2):
if not head1:
return head2
if not head2:
return head1
current1 = head1
current2 = head2
if current2.val>=current1.val:
new_head = head1
end = head1
current1 = current1.next
else:
new_head = head2
end = head2
current2 = current2.next
while current1 and current2:
if current2.val>=current1.val:
end.next = current1
end = current1
current1 = current1.next
else:
end.next = current2
end = current2
current2 = current2.next
if current1:
end.next = current1
if current2:
end.next = current2
return new_head
merge2Lists函数是通用的,用来代替归并里的merge,上面的逻辑和归并就真的一样了,写完一次过,也是挺爽的。看看时间复杂度,leetcode上跑的:
总的速度比刚看了四十倍呀,时间复杂度为
O
(
k
l
o
g
k
n
)
O(klogkn)
O(klogkn)
应该还有更快的解法,毕竟才超过了百分之70,水平有限就写到这里吧,有更好解法再更新。