23. Merge k Sorted Lists (Python)暴力+分治+最小堆

23. Merge k Sorted Lists

Hard

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

Example:

Input:
[
  1->4->5,
  1->3->4,
  2->6
]
Output: 1->1->2->3->4->4->5->6

 

笔记:

1. 解法一 (暴力) 

每次合并两个,然后用新合并的去跟第三个合并。

比如:合并a,b,c,d

先ab合并,将头节点赋值给a,然后ac合并,将头节点赋值给a,然后合并ad,将头节点赋值给a,最后返回a

LeeCode上面返回的运行时间如下:

class Solution:
    def mergeKLists(self, lists):
        if not lists:
            return None
        n = len(lists)
        i = 1
        while i < n:
            lists[0] = self.merge_two_lists(lists[0], lists[i])
            i += 1
        return lists[0]


    def merge_two_lists(self, list1, list2):
        current_head = ListNode()
        return_head = current_head
        while list1 and list2:
            if list1.val <= list2.val:
                current_head.next = list1
                current_head = current_head.next
                list1 = list1.next
            else:
                current_head.next = list2
                current_head = current_head.next
                list2 = list2.next
        current_head.next = list2 if not list1 else list1
        return return_head.next

2. 分治 (divide and 从conquer)

将所有的链表分成两个部分,然后对应合并两个链表,比如 链表1,2,3,4,5,6. 先合并1-4,2-5,3-6,然后合并1-4-3-6,最后合并1-4-3-6-2-5。

LeeCode上面的运行时间为124ms,对面暴力的4612ms,速度明显提升很多。

class Solution:
    def mergeKLists(self, lists):
        if not list:
            return None
        n = len(lists)

        while n > 1:
            k = (n + 1) // 2
            for i in range(n//2):
                lists[i] = self.merge_two_lists(lists[i], lists[i + k])
            n = k
        return lists[0]


    def merge_two_lists(self, list1, list2):
        current_head = ListNode()
        return_head = current_head
        while list1 and list2:
            if list1.val <= list2.val:
                current_head.next = list1
                current_head = current_head.next
                list1 = list1.next
            else:
                current_head.next = list2
                current_head = current_head.next
                list2 = list2.next
        current_head.next = list2 if not list1 else list1
        return return_head.next

3. 利用最小堆

思路:创建一个空的节点head,方便找到合并后的头节点(head.next),然后创建tail_node变量指向head节点,此节点为当前合并链的尾结点。首先将每条链的头节点放入到创建的堆中,此时堆顶的节点就是当前值最小的节点。弹出堆顶的节点,将tail节点的next指向当前弹出的节点(cur_node), 并修改tail_node节点为cur_node。如果cur_node的next还有节点,将cur_node.next压入到堆中,如果cur_node.next为None,不做任何处理。接着继续弹出堆顶的节点,进行如上操作,知道堆为空,则合并完毕。最后合并完的链表的头节点则为head.next

python 中使用heapq 库中的函数来创建堆,相关函数如下:

需要注意的是,heapify(heap)中的heap必须是一个list. 在Python3 中,不能直接使用node节点作为 堆的元素,比如heappush(heap, (node.val, node)), 这样是会报错的。正确的用法是 heappush(heap, (node.val, index))。确保堆中的数据可以直接比较 。所以在下面的代码中使用了节点的索引,因为使用了索引,所以需要更新lists中对应索引的节点,也就是代码中的

lists[cur_node_index] = cur_node.next

 

运行时间:

class Solution:
    def mergeKLists(self, lists):
        if not lists:
            return None
        heap = []
        for index, node in enumerate(lists):
            if node:
                heap.append((node.val, index))
        heapq.heapify(heap)

        head = ListNode()
        tail_node = head
        while heap:
            cur_node_index = heapq.heappop(heap)[1]
            cur_node = lists[cur_node_index]
            if cur_node.next:
                heapq.heappush(heap, (cur_node.next.val, cur_node_index))
                lists[cur_node_index] = cur_node.next
            tail_node.next = cur_node
            tail_node = cur_node
        return head.next

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值