提问者:小点点

在python3中使用heapq模块合并k个排序列表


问题:-合并k个排序列表。

我想使用min heap解决这个问题,它可以在python中使用heapq模块实现。下面是函数的示例代码…

heapq.heappush(listwithoutNone,(node.val, node))
        

但问题是python解释器引发了一个错误:

类型错误:'

所以,我想使用node. val作为minheap节点元素,因为我传递的是一个元组,所以我应该在代码中做什么更改,以便minheap使用node.val堆。

提前感谢。


共3个答案

匿名用户

比较元组时,会比较它们的第一个元素,然后使用它们的第二个元素、它们的元素等打破任何联系。例如,(2,"a")

在这里,您将(node. val,node)元组插入到堆中,堆会尝试比较它们。如果节点值有平局,它会移动到元组的第二个元素-节点本身。这些只是ListNode实例。Python不知道如何比较两个ListNodes,因此出错。

要在ListNodes之间启用比较,您需要实现丰富的比较方法。一个快速的方法是简单地实现ListNode。__lt__,然后使用功能工具。total_ordering装饰器:

import heapq
from functools import total_ordering


@total_ordering
class ListNode:
    def __init__(self, value: float, label: str) -> None:
        self.value = value
        self.label = label

    def __lt__(self, other: 'ListNode'):
        return self.value <= other.value

    def __str__(self):
        return f"ListNode(label={self.label}, value={self.value})"



nodes = []
a =  ListNode(5, "A")
b = ListNode(3, "B")
c = ListNode(5, "C")
heapq.heappush(nodes, a)
heapq.heappush(nodes, b)
heapq.heappush(nodes, c)

while nodes:
    x = heapq.heappop(nodes)
    print(x)

这里我们说比较两个ListNode对象和仅仅比较它们的值是一样的。定义了比较,你甚至根本不需要插入元组。你可以直接插入ListNode对象,并依赖比较方法。

匿名用户

我想你说的是这个:Leetcode合并k排序列表

我为您分享一个工作解决方案:

head = curr = ListNode(0)    # Creating a dummy node
    lst = []
    for l in lists:
        if l:
 # Here we need to first push val so that heap can know which is minimum and which is maximum. 
 # If we insert directly node then heap can't work proper way (in this case heapq.heappop doesn't return minimum node).    
            lst.append((l.val,l))    

    
    heapq.heapify(lst)
    while lst:
        val,node = heapq.heappop(lst)
        curr.next = node
        curr = curr.next
        node = node.next
        if node:
            heapq.heappush(lst,(node.val,node))
    return head.next 

匿名用户

为了改进Saurabh的答案,您可以在迭代各个列表时生成最终的排序列表。

这个想法是首先用每个排序数组的第一个元素填充堆,并用元素来自的数组标记,每当从堆中弹出时,添加与刚刚从堆中弹出的元素关联的数组的下一个元素。

def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
    heap = []
    for i, l in enumerate(lists):
        if l is None:
            continue
        heapq.heappush(heap, (l.val,i))
        lists[i] = lists[i].next

    out = ListNode() # dummy
    cur = out
    while heap:
        val, i = heapq.heappop(heap)
        cur.next = ListNode(val)
        cur = cur.next
        if lists[i] is not None:
            heapq.heappush(heap, (lists[i].val, i))
            lists[i] = lists[i].next
    return out.next

这也可以修改,以便堆跟踪实际节点,这样就不会创建新节点(除了虚拟头):

def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
    heap = []
    for i, l in enumerate(lists):
        if l is None:
            continue
        heapq.heappush(heap, (l.val, i, l))
        lists[i] = lists[i].next

    out = ListNode() # dummy
    cur = out
    while heap:
        val, i, node = heapq.heappop(heap)
        cur.next = node
        cur = cur.next
        if lists[i] is not None:
            heapq.heappush(heap, (lists[i].val, i, lists[i]))
            lists[i] = lists[i].next
    return out.next

堆将只包含最大的k元素,其中k是进审量列表。因此,我们解决了@Abhishek Jaiswal关于空间复杂度应该是O(k)的担忧。

编辑:添加空间复杂度改进分析