当前位置: 首页>后端>正文

23. 合并K个排序链表

题目描述:

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

示例:

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6

优先级队列的概念:

参考:

  • https://www.cnblogs.com/xzxl/p/7266404.html
  • https://blog.csdn.net/pzhu_cg_csdn/article/details/79166858

优先级队列与普通队列一样,只能从队尾插入元素,从队首删除元素。但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。优先级队列底层是用堆实现的。

Python的PriorityQueue是用 heapq 实现的。( https://blog.csdn.net/liu2012huan/article/details/53264162 )

代码:

from Queue import PriorityQueue
# 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
        """
        q = PriorityQueue(maxsize=len(lists))
        cur = dummy = ListNode(None)
        for idx, node in enumerate(lists):
            if node:
                q.put((node.val, idx, node))
        while q.qsize() > 0:
            _, idx, cur.next = q.get() # get()会将节点弹出
            cur = cur.next
            if cur.next:
                q.put((cur.next.val, idx, cur.next))
        return dummy.next

这里有一些细节需要注意:

  • 优先级队列需要明确将哪个量设置为优先级的评价标准,这里 node.val 就是用来作为这一标准的;
  • 为什么还要引入 idx ?这是因为如果“第一评价标准”的优先级相同(这里即为 node.val ),代码就会比较“第二评价标准”。这里如果不设置“第二评价标准”,代码便会将 node 作为“第二评价标准”,而 node 是一个节点类,可能没有重写比较的方法,此时代码就会报错(这便是在 https://leetcode.com/problems/merge-k-sorted-lists/discuss/10511/10-line-python-solution-with-priority-queue 中 @ __fibo__ 提到的问题)。因此必须要找一个辅助变量作为“第二评价标准”,这里选取的是节点在列表中的索引。

复杂度分析:(强烈建议参考: https://blog.csdn.net/hellozhxy/article/details/81055397 )

前已述及,优先级队列的底层是用堆实现的。因此往一个长度为 23. 合并K个排序链表,n,第1张 的优先级队列中插入一个元素的时间复杂度为 23. 合并K个排序链表,O(\log n),第2张 。如果总共有 23. 合并K个排序链表,m,第3张 个元素,则将这 23. 合并K个排序链表,m,第3张 个元素插入这个长度为 23. 合并K个排序链表,n,第1张 的优先级队列中的时间复杂度为 23. 合并K个排序链表,O(m \log n),第6张

现在代码中优先级队列的最大长度为 23. 合并K个排序链表,k,第7张 ,把最初的 23. 合并K个排序链表,k,第7张 个头结点插入这个优先级队列的时间复杂度为 23. 合并K个排序链表,O(k \log k),第9张

关于时间复杂度的分析,@ gulshan98125 认为:假设 23. 合并K个排序链表,n,第1张 是所有链表中最长的链表长度,现在总共有 23. 合并K个排序链表,k,第7张 个链表,则总的时间复杂度为 23. 合并K个排序链表,O(nk \log k),第12张 ;而 @spitza 认为,把 23. 合并K个排序链表,n,第1张 当成是 23. 合并K个排序链表,k,第7张 个链表中所有的节点个数显得更直观一些,这样一来时间复杂度将会变成 23. 合并K个排序链表,O(n \log k),第15张 。我个人的观点是,把 23. 合并K个排序链表,n,第1张 当成是这 23. 合并K个排序链表,k,第7张 个链表的平均长度,这样时间复杂度为 23. 合并K个排序链表,O(nk \log k),第12张

空间消耗在于维护一个长度为 23. 合并K个排序链表,k,第7张 的优先级队列(其实是维护一个容量为 23. 合并K个排序链表,k,第7张 的堆),因此空间复杂度为 23. 合并K个排序链表,O(k),第21张


https://www.xamrdz.com/backend/3kj1920601.html

相关文章: