leetcode23. 合并K个排序链表

leetcode23. 问题描述

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

解题思路:1.暴力循环求解,不知道为啥不管碰到啥题,能用暴力解决的我绝不多想,可能我思想比较暴力?不多说,先感受一下暴力的快感吧。
  想法很简单,K个有序链表,先把1号链表和2号链表合并得到一个新的有序链表,把新链表和3号链表合并得到新链表,然后继续循环,把K个链表循环完最后的链表就是合并后的链表。用一句话来说,用一个新的空链表来遍合并K个链表,将上一次得到的新链表加入下次合并中。
  其中,一直要用的函数就是两个有序链表的合并函数,基本思路如下:判断两个链表的头结点,选择值最小的作为新的头结点,如果相同选择第一个作为新头结点,然后用current1和current2指针,分别指向还没有加入到新链表的剩余有序链表。并用一个end指针来维护新链表的数组尾部,判断current1和current2值大小,不断加入到新链表中来。下图表示其中一个状态向另外一个状态的过度

  直到某个链表循环结束,我们用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,水平有限就写到这里吧,有更好解法再更新。

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值