目录
1.题目
描述
数据流是一个实时的、连续的、有序的项目序列。一些示例包括传感器数据、Internet流量、金融报价、在线拍卖和事务日志(如Web使用日志和电话记录)。同样,流上的查询在一段时间内连续运行,并在新数据到达时递增地返回新结果。例如,工厂仓库的温度检测系统可能运行如下查询。
查询-1:“每隔五分钟,检索过去五分钟内的最高温度。”
查询-2:“返回过去10分钟内每层楼的平均温度。”
我们开发了一个名为Argus的数据流管理系统,它可以处理数据流上的查询。用户可以向Argus注册查询。Argus将在不断变化的数据上保持查询运行,并以期望的频率将结果返回给相应的用户。
对于Argus,我们使用以下指令注册查询:
Register Q_num Period
Q_num (0 < Q_num <= 3000)为查询的ID-number, Period (0 < Period <= 3000)为查询结果连续两次返回的时间间隔。在注册周期秒后,第一次返回结果,之后每周期秒返回一次结果。
这里我们一次在Argus中注册了几个不同的查询。确认所有查询都有不同的Q_num。您的任务是告诉前K个查询返回结果。如果两个或多个查询要同时返回结果,它们将按照Q_num的升序依次返回结果。
输入
输入的第一部分是给Argus的寄存器指令,每行一个指令。您可以假设指令的数量不会超过1000条,并且所有这些指令都是同时执行的。这部分以一行“#”结束。
第二部分是你的任务。这部分只包含一行,是一个正整数K(<= 10000)。
输出
您应该输出前K个查询的Q_num以返回结果,每行一个数字。
样例输入
Register 2004 200 Register 2005 300 # 5
样例输出
2004 2005 2004 2004 2005
我们先根据样例输入和输出来读题,样例输入两个查询号,2004和2005。其中2004的查询时间是200s(权当1周期秒是1秒),2005查询时间是300s。输出先经过200秒输出2004,再过100秒输出2005,再过100秒,这时离第一次输出2004已经过了200秒,输出2004。再过200秒,这个时候2004和2005应当同时输出,所以按照升序排列输出,先输出2004,再输出2005.
题目说输出前5个任务,即输出
2004 2005 2004 2004 2005
下面画一幅图帮助理解
好,我们现在来观察样例输出,是不是很像下面这张图片
嗯,这个就是数据结构里的堆
2.开始吹水
1.堆是什么
堆(heap):一种有特殊用途的数据结构——用来在一组变化频繁(发生增删查改的频率较高)的数据集中查找最值。
堆在逻辑结构上,一般被视为是一颗完全二叉树。
2.堆的分类
堆分为最大堆和最小堆,在最大堆中,父节点总是比子节点大,而最小堆相反。
3.堆属性
设i为数组下标
如果 i 为0,则 i 表示的节点为根节点,否则i节点的双亲节点为 (i - 1)/2;
如果2 * i + 1 小于节点个数,则节点i的左孩子下标为2 * i + 1,否则没有左孩子;
如果2 * i + 2 小于节点个数,则节点i的右孩子下标为2 * i + 2,否则没有右孩子。
因为这道题需要按照时间顺序输出最先到达时间点的K个查询,而且如果多个查询在同一时间到达,则需要按照查询ID升序输出。依照题意,我们需要用到最小堆来存储数据。
而python中刚好有一个名为heapq的最小堆的库,我们的问题刚刚好就要用到这个库。
3.回到题目(不想看吹水的可以先看这里)
这道题需要按照时间顺序输出最先到达时间点的K个查询,所以我们利用heappush()方法创建一个最小堆并把需要查询的ID和对应的周期秒放入堆中。
heapq.heappush(heap, item)
是一个 Python 内置函数,用于将元素 item
加入到 heap
中。其中 heap
是一个列表,它表示一个堆。这个方法会将元素 item
加入到堆中,并按照堆的规则调整堆,使得堆的根节点(即最小元素)在堆顶,保证堆是有序的。
这样最先查询到的数字就被放在最前面了,现在就差输出了,方法是heappop()
heapq.heappop(heap)
是 Python 的一个堆操作方法,用于从堆中弹出最小的元素并返回该元素。
下面是完整的代码
import heapq
# 定义一个堆来存储各个任务
heap = []
# 读入每个任务的信息,按照周期将任务加入堆中
while True:
s = input().strip()
if s == "#":
break
# _ 表示无用的返回值,这里用 _ 来忽略第一个数(就是那个Register)
_, q_num, period = s.split()
heapq.heappush(heap, (int(period), int(q_num), int(period)))
# 读入需要查询的次数
k = int(input())
# 对于每次查询,从堆中取出下一个周期最小的任务,并输出其任务编号
for _ in range(k):
period, q_num, init_period = heapq.heappop(heap)
print(q_num)
# 将该任务的下一次周期加入堆中
heapq.heappush(heap, (period+init_period, q_num, init_period))