【Leetcode周赛】第243场周赛 T3 - 1882. 使用服务器处理任务 - 中等(堆/优先队列)
题目描述
给你两个下标从
0
开始 的整数数组servers
和tasks
,长度分别为n
和m
。servers[i]
是第i
台服务器的权重 ,而tasks[j]
是处理第j
项任务所需要的时间(单位:秒)。
你正在运行一个仿真系统,在处理完所有任务后,该系统将会关闭。每台服务器只能同时处理一项任务。第0
项任务在第0
秒可以开始处理,相应地,第j
项任务在第j
秒可以开始处理。处理第j
项任务时,你需要为它分配一台 权重最小 的空闲服务器。如果存在多台相同权重的空闲服务器,请选择 下标最小 的服务器。如果一台空闲服务器在第t
秒分配到第j
项任务,那么在t + tasks[j]
时它将恢复空闲状态。
如果没有空闲服务器,则必须等待,直到出现一台空闲服务器,并 尽可能早 地处理剩余任务。 如果有多项任务等待分配,则按照 下标递增 的顺序完成分配。
如果同一时刻存在多台空闲服务器,可以同时将多项任务分别分配给它们。
构建长度为m
的答案数组ans
,其中ans[j]
是第j
项任务分配的服务器的下标。
返回答案数组ans
。
示例 1:
输入:servers = [3,3,2]
,tasks = [1,2,3,2,1,2]
输出:[2,2,0,2,1,2]
解释:事件按时间顺序如下:
- 0 秒时,第 0 项任务加入到任务队列,使用第 2 台服务器处理到 1 秒。
- 1 秒时,第 2 台服务器空闲,第 1 项任务加入到任务队列,使用第 2 台服务器处理到 3 秒。
- 2 秒时,第 2 项任务加入到任务队列,使用第 0 台服务器处理到 5 秒。
- 3 秒时,第 2 台服务器空闲,第 3 项任务加入到任务队列,使用第 2 台服务器处理到 5 秒。
- 4 秒时,第 4 项任务加入到任务队列,使用第 1 台服务器处理到 5 秒。
- 5 秒时,所有服务器都空闲,第 5 项任务加入到任务队列,使用第 2 台服务器处理到 7 秒。
示例 2:
输入:servers = [5,1,4,3,2]
,tasks = [2,1,2,4,5,2,1]
输出:[1,4,1,4,1,3,2]
解释:事件按时间顺序如下:
- 0 秒时,第 0 项任务加入到任务队列,使用第 1 台服务器处理到 2 秒。
- 1 秒时,第 1 项任务加入到任务队列,使用第 4 台服务器处理到 2 秒。
- 2 秒时,第 1 台和第 4 台服务器空闲,第 2 项任务加入到任务队列,使用第 1 台服务器处理到 4 秒。
- 3 秒时,第 3 项任务加入到任务队列,使用第 4 台服务器处理到 7 秒。
- 4 秒时,第 1 台服务器空闲,第 4 项任务加入到任务队列,使用第 1 台服务器处理到 9 秒。
- 5 秒时,第 5 项任务加入到任务队列,使用第 3 台服务器处理到 7 秒。
- 6 秒时,第 6 项任务加入到任务队列,使用第 2 台服务器处理到 7 秒。
提示:servers.length == n
tasks.length == m
1 <= n, m <= 2 * 10^5
1 <= servers[i], tasks[j] <= 2 * 10^5
解题思路
这道题目的题干和示例都很长,所以就要求我们能从中提取有效信息,将阅读题抽象成算法题,再挑选合适的数据结构和算法来解决。
先分析下服务器的分配原则,即优先分配空闲服务器中权重最小的服务器,不难看出这是个动态分配的过程,即下次会分配新的空闲服务器中下一个权重最小的服务器,我们可以每次都去找符合条件的最小值,但是每次都需要遍历一遍数组,时间复杂度为$\mathcal{O}(N)$。
这时我们应该想到用堆这个数据结构也就是优先队列来处理动态极值的问题,因为我们只关心当前权重最小的服务器,这样无论是分配空闲服务器还是将已经完成工作的服务器放回空闲服务器的时间复杂度都为$\mathcal{O}(logN)$,先设置一个优先队列pq_free
处理空闲服务器,其中的元素为(权重,下标)
,这样就达到了“优先比权重,权重相同比下标”的目的。
然后我们发现最先完成工作的服务器优先压回到pq_free
中,又是一个动态极值的问题,那么我们可以再为正在工作的服务器设置一个优先队列pq_busy
,其中的元素为(预计完成时刻,权重,下标)
。这样服务器就可以无缝在这两个状态之间转换,即在两个优先队列之间“流动”。
确定完数据结构还需要注意两点:
1. “如果同一时刻存在多台空闲服务器,可以同时将多项任务分别分配给它们。”,即为一个任务分配完服务器后先别急着递加时间,先判断同一时刻是否还有空闲服务器以及下一个任务是否准备就绪。
2. 当pq_free
为空时,我们不需要再慢慢递加时间t
,直接将t
设为pq_busy
中队首元素对应的预计完成时刻
即可,这样可以降低复杂度,如果不这样做其实也没法通过所有用例。
代码(Python)
1 | class Solution: |