堆是一种二叉树结构,python中的堆是小根堆。每个父节点的值都小于或等于它的任何子节点;即对于任何一个结点 k k k,都满足:
a[k] <= a[2*k+1]
a[k] <= a[2*k+2]
最小的元素总是根元素。
heapq模块是通过堆实现的优先队列算法
方法 | 功能 |
---|---|
heapq.heappush(heap, item) | 将 item 的值加入heap中,保持堆的性质。 |
heapq.heappop(heap) | 弹出并返回heap的最小的元素,保持堆的性质。如果堆为空,抛出 IndexError。 heap[0] 访问最小的元素而不弹出它 |
heapq.heappushpop(heap, item) | 将item放入堆中,弹出并返回heap的最小元素 |
heapq.heapify(x) | 将list x 转换成堆,原地,线性时间内。 |
heapq.heapreplace(heap, item) | 弹出并返回 heap 中最小的一项,同时推入新的 item。 堆的大小不变。 如果堆为空则引发 IndexError |
heapq.merge(*iterables, key=None, reverse=False) | 将多个已排序的输入合并为一个已排序的输出。 返回已排序值的 iterator |
heapq.nlargest(n, iterable, key=None) | 从iterable 所定义的数据集中返回前n个最大元素组成的列表 |
heapq.nsmallest(n, iterable, key=None) | 从 iterable 所定义的数据集中返回前 n 个最小元素组成的列表 |
插入删除元素
从堆中插入或者删除元素,元素可以是元组(比较大小根据是元组中的第一个数)
import heapq
h = []
heapq.heappush(h, (5, 'write code'))
# 插入元素
heapq.heappush(h, (7, 'release product'))
heapq.heappush(h, (1, 'write spec'))
heapq.heappush(h, (3, 'create tests'))
heapq.heappop(h)
# 删除根结点
print(h)
[(3, 'create tests'), (7, 'release product'), (5, 'write code')]
用于排序
堆排序可以通过将所有值压入堆中,然后每次取出最小值来实现:
import heapq
def heapsort(iterable):
h = []
for value in iterable:
heapq.heappush(h, value)
return [heapq.heappop(h) for _ in range(len(h))]
res = heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
print(res)
以上翻译自:https://docs.python.org/3/library/heapq.html
应用
对于示例1,[1,2,3,3,4,5]
,遍历元素,假设是x,将元素插入到长度最短并且以x-1结尾的列表中,如果没有,则单独作为列表插入。最后判断是否所有的列表是否都大于等于3或者为空。
插入1
[[1]
插入2
[[1,2]]
插入3
[[1,2,3]]
插入3
[[1,2,3],[3]]
插入4,插入到以3结尾,并且长度最短的列表中
[[1,2,3],[3,4]]
插入5
[[1,2,3],[3,4,5]]
结束,符合要求
这里并不需要真正使用列表,执行插入操作,因为知道以什么结尾,长度是多少,就等于知道了这个列表长啥样。
关键在于如何找到以x-1结尾,并且长度最短的列表。
将以x-1结尾的所有列表的长度,存成一个堆,每次pop最小的长度
插入x 等价于,以x结尾的长度堆,插入一个新的长度;
对应代码如下:
class Solution:
def isPossible(self, nums) -> bool:
mp = collections.defaultdict(list)
# key 最后一个值
# value 对应的长度,list
for x in nums:
queue = mp.get(x - 1)
# 找出以x-1结尾的子序列的长度list
if queue:
prevLength = heapq.heappop(queue)
# 找出以x-1结尾的子序列的最小长度
heapq.heappush(mp[x], prevLength + 1)
else:
heapq.heappush(mp[x], 1)
# queue[0] 长度最短的是否小于3
return not any(queue and queue[0] < 3 for queue in mp.values())