巧用优先队列征服LeetCode 23:合并K个升序链表
2023-09-03 10:27:06
亲爱的小伙伴们,今天,我们踏上了一段探索如何合并多个升序链表的征程,而我们的秘密武器就是优先队列,准备好了吗?让我们开始吧!
优先队列:小顶堆的奇妙世界
小顶堆是一种数据结构,它可以高效地存储和管理一系列元素,并始终将最小值保存在堆顶。在我们的任务中,我们将使用小顶堆来存储每个链表的头节点。
每次,我们从堆顶弹出最小值,然后将其余节点加入到堆中。这样,我们就能一步一步地合并链表,直到所有元素都被合并到一个升序链表中。
算法流程:一步一步合并
- 初始化优先队列: 将每个链表的头节点加入到优先队列中。
- 循环合并:
- 从堆顶弹出最小值的链表头节点,加入到合并后的链表中。
- 将该链表的头节点指向下一个节点,如果存在的话。
- 如果该链表还有剩余节点,将其头节点加入到优先队列中。
- 重复步骤 2, 直到优先队列为空,即所有链表都已被合并。
代码示例:清晰易懂的实现
import heapq
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
# 初始化优先队列
heap = []
for node in lists:
if node:
heapq.heappush(heap, (node.val, node))
# 循环合并
dummy = ListNode()
current = dummy
while heap:
# 从堆顶弹出最小值
val, node = heapq.heappop(heap)
# 合并到最终链表中
current.next = node
current = current.next
# 将剩余节点加入到堆中
if node.next:
heapq.heappush(heap, (node.next.val, node.next))
return dummy.next
示例:一步步理解合并过程
假设我们有三个升序链表:
- L1:1 -> 4 -> 5
- L2:1 -> 3 -> 4
- L3:2 -> 6
初始化:
优先队列:[(1, L1), (1, L2), (2, L3)]
步骤 1:
从堆顶弹出最小值:(1, L1)
合并后的链表:1
L1:4 -> 5
优先队列:[(1, L2), (2, L3)]
步骤 2:
从堆顶弹出最小值:(1, L2)
合并后的链表:1 -> 1
L2:3 -> 4
优先队列:[(2, L3)]
步骤 3:
从堆顶弹出最小值:(2, L3)
合并后的链表:1 -> 1 -> 2
L3:6
优先队列:[(4, L1), (3, L2), (6, L3)]
步骤 4:
从堆顶弹出最小值:(3, L2)
合并后的链表:1 -> 1 -> 2 -> 3
L2:4
优先队列:[(4, L1), (6, L3)]
步骤 5:
从堆顶弹出最小值:(4, L1)
合并后的链表:1 -> 1 -> 2 -> 3 -> 4
L1:5
优先队列:[(6, L3)]
步骤 6:
从堆顶弹出最小值:(6, L3)
合并后的链表:1 -> 1 -> 2 -> 3 -> 4 -> 6
最终合并后的链表为:1 -> 1 -> 2 -> 3 -> 4 -> 6
结语
至此,我们已经掌握了使用优先队列合并多个升序链表的技术,这让我们在解决链表相关问题时有了强大的武器。希望这篇文章对你有帮助,让我们继续探索算法世界的奇妙之处吧!