LeetCode合并K个升序链表(python版)

一、描述

 

   给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。

   示例 1:

      输入:lists = [[1,4,5],[1,3,4],[2,6]]
      输出:[1,1,2,3,4,4,5,6]
      解释:链表数组如下:
      [
        1->4->5,
        1->3->4,
        2->6
      ]
      将它们合并到一个有序链表中得到。
      1->1->2->3->4->4->5->6


    示例 2:

       输入:lists = []
       输出:[]


     示例 3:

输入:lists = [[]]
       输出:[]

     提示:

        k == lists.length
        0 <= k <= 10^4
        0 <= lists[i].length <= 500
        -10^4 <= lists[i][j] <= 10^4
        lists[i] 按 升序 排列
        lists[i].length 的总和不超过 10^4

 

二、理解

      首先,意识到数组中每个元素是一个链表,要注意和列表的区别;其次,每个链表都是升序的,因此两个链表合二为一可以在线性时间内完成。

      思路

          将前两个链表合二为一,将新链表与第三个链表合二为一,......,将新链表与第n个链表合二为一。

      一些特殊情况为

           空数组,直接返回,没有返回值,有返回值便通不过,不知是LeetCode的问题还是我理解的有问题;只有一个链表,直接返回链表头。

       小技巧

           提示中说明了链表元素的最小值是-10000,可提前生成一个值为-10001的链表头,否则你要在两个链表的首元素中选择一个作为链表头。

           这也是为何第三部分代码最后一行是 return head.next 而不是 return head 的原因。

 

三、代码(初级版)

class ListNode(object):
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        k = len(lists)
        head = ListNode(val=-10001)
        tail = head
        if k == 0: return
        if k == 1: return lists[0]

        lp = lists[0]
        rp = None

        i = 1
        # 将已完成合并的链表与当前链表数组中的第i个链表进行合并
        while i < k:
            rp = lists[i]
            while lp and rp:
                if lp.val <= rp.val:
                    tail.next = lp
                    tail = lp
                    lp = lp.next
                else:
                    tail.next = rp
                    tail = rp
                    rp = rp.next
            if rp: tail.next = rp
            if lp: tail.next = lp
            i += 1
            # 如果数组没有遍历完,则重置头指针和尾指针
            if i < k:
                lp = head.next
                head.next = None
                tail = head
        return head.next

上述代码虽然通过了测试,但下述结果并不是特别理想。

执行用时:3916 ms, 在所有 Python 提交中击败了15.47%的用户

内存消耗:19.1 MB, 在所有 Python 提交中击败了41.84%的用户

算法复杂度为 O(n^2),n 为所有的链表节点数。

 

四、优化版

    在优化版本中,注意是意识到了可以效仿归并排序的做法,下面是代码。

   

# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, val=0, nxt=None):
        self.val = val
        self.next = nxt

class Solution(object):

    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        k = len(lists)
        if k == 0: return
        if k == 1: return lists[0]

        mid = k / 2
        lp = self.mergeKLists(lists[0:mid])
        rp = self.mergeKLists(lists[mid:])

        head = ListNode(val=-10001)
        tail = head
        while lp and rp:
            if lp.val <= rp.val:
                tail.next = lp
                tail = lp
                lp = lp.next
            else:
                tail.next = rp
                tail = rp
                rp = rp.next
        if lp: tail.next = lp
        if rp: tail.next = rp
        return head.next

这次的执行结果

执行用时:92 ms, 在所有 Python 提交中击败了73.96% 的用户

内存消耗:18.9 MB, 在所有 Python 提交中击败了43.94% 的用户

算法复杂度为 O(nlogn),n 为所有的链表节点数。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值