leetcode 23. Merge k Sorted Lists Python3 多解

一.问题描述

You are given an array of k linked-lists lists, each linked-list is sorted in ascending order.

Merge all the linked-lists into one sorted linked-list and return it.

 

Example 1:

Input: lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
Explanation: The linked-lists are:
[
  1->4->5,
  1->3->4,
  2->6
]
merging them into one sorted list:
1->1->2->3->4->4->5->6

Example 2:

Input: lists = []
Output: []

Example 3:

Input: lists = [[]]
Output: []

 

Constraints:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i] is sorted in ascending order.
  • The sum of lists[i].length won't exceed 10^4.

二.解题思路

这道题的解决方法可能比较多,根据实现的不同主要讲3种。

<1>

拿到题目,很容易想到的一个解法就是迭代lists种每个链表的第一个元素,然后比较它们的大小,把最小的加入到结果变量中,然后将所取的最小元素的那个链表的头指向下一个位置,重复。

时间复杂度 O(MN),M为lists的长度,N为所有链表的元素总数。

<2>优先队列

思路和上面类似,但是此时我们用一个优先队列来储存所有链表的第一个元素,使得这个队列的头永远是最小值,即每次pop出来的链表,它的第一个元素的值是最小的。维护这样一个数据结构(二叉小顶堆实现),每次调整需要 O(logN),一个M次,因此整个的时间复杂度: O(N*log(M))。

<3>分治法,divide and conquer

将lists切分为两等份,即左半部和右半部分,合并左右两部分处理的结果链表来得到最后结果。迭代一直切分,直到最小的分治单位2。

换个思路,从下往上理解就是,首先两两合并lists中的链表,比如第一和第二个链表合并,然后保存到临时变量中,第三和第四个链表合并,保存到临时变量中。迭代完一次后,

判断该临时变量是否长度为1,不为1就按照上述步骤继续两两合并。

时间复杂度:每一次要合并N个数,一共log(M)次,O(N*log(M))

PS:以下内容可不看,同样的方法,下面的实现可能不易于理解。

不开新的临时变量也可以,就需要在迭代的时候动动手脚,

步长指的是迭代的时候,每隔多少取一个元素。

首先设置步长为2,然后每2个一组合并,即i与i+步长/2的两个链表合并,结果保存就保存到lists[i],即与相应位置的链表替换。然后跳到下一个位置j=i+步长/2,直至遍历完一次lists。

然后步长*2,和上述一样操作,直至步长超过lists的长度。

主要需要理解的一个地方就是,lists的长度可能不是被步长整除啊,会不会漏掉呢,

其实不会,假设当前最后一个链表无法被当前步长覆盖(即合并),在下一个步长的时候,它一定会被覆盖掉。

可以自己理解以下,比如 1,2,3,4,5. 首先步长为2,就是1,3合并,然后5的信息漏了,到步长为4的时候,就到1,5合并了。

具体需要看代码,注意边界问题。

三. 源码

注:

方法二代码来自:方法二

方法三易于理解版来自: 方法三易于理解版

# 方法<1>
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        lists=[l for l in lists if l]
        if not lists:
            return None
        ln=ListNode()
        head=ln
        while lists:
            ln.next=ListNode()
            ln=ln.next
            min_cur=10**4+1
            min_idx=-1
            for i,l in enumerate(lists):
                if l.val<min_cur:
                    min_idx=i
                    min_cur=l.val
            ln.val=min_cur
            lists[min_idx]=lists[min_idx].next
            if lists[min_idx]==None:
                del lists[min_idx]
        return head.next

# 方法<2> 
import heapq
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        heap = [(node.val, idx, node) for idx, node in enumerate(lists) if node]
        heapq.heapify(heap)
        
        pre_head = ListNode()
        node = pre_head
        while heap:
            _, idx, popped_node = heapq.heappop(heap)
            if popped_node.next:
                heapq.heappush(heap, (popped_node.next.val, idx, popped_node.next))
                
            node.next = popped_node
            node = node.next                
                
        return pre_head.next

# 方法<3> 易于理解版
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        if not lists:
            return None
        while len(lists)>1:
            A = lists.pop(0)
            B = lists.pop(0)
            head =ListNode(0)
            temp = head
            while A and B:
                if A.val<=B.val:
                    temp.next = A
                    A = A.next
                else:
                    temp.next = B
                    B = B.next
                temp = temp.next
            temp.next = A or B
            lists.append(head.next)
        return lists[0]

# 方法<3>, 直接lists上操作
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:     
        def mergeTwoLists(l1,l2):
            cur=ListNode()
            head=cur
            while l1 and l2:
                if l1.val < l2.val:
                    cur.next = l1
                    l1 = l1.next
                else:
                    cur.next = l2
                    l2 = l2.next  
                cur=cur.next
            if l1:
                cur.next = l1
            if l2:
                cur.next = l2
            return head.next
        
        lists=[l for l in lists if l]
        if not lists:return None
        l=len(lists)
        interval=1
        while interval<l:
            for i in range(0,l-interval,2*interval):
                lists[i]=mergeTwoLists(lists[i],lists[i+interval])
            interval*=2
        return lists[0]

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值