优先级队列的应用 II
应用
应用1:Leetcode 1834. 单线程 CPU
题目
给你一个二维数组 tasks ,用于表示 n 项从 0 到 n - 1 编号的任务。其中
意味着第 i 项任务将会于 enqueueTimei 时进入任务队列,需要 的时长完成执行。
现有一个单线程 CPU ,同一时间只能执行 最多一项 任务,该 CPU 将会按照下述方式运行:
如果 CPU 空闲,且任务队列中没有需要执行的任务,则 CPU 保持空闲状态。
如果 CPU 空闲,但任务队列中有需要执行的任务,则 CPU 将会选择 执行时间最短 的任务开始执行。如果多个任务具有同样的最短执行时间,则选择下标最小的任务开始执行。
一旦某项任务开始执行,CPU 在 执行完整个任务 前都不会停止。
CPU 可以在完成一项任务后,立即开始执行一项新任务。
返回 CPU 处理任务的顺序。
示例 1:
输入:
输出:
解释:事件按下述流程运行:
- time = 1 ,任务 0 进入任务队列,可执行任务项 = [0]
- 同样在 time = 1 ,空闲状态的 CPU 开始执行任务 0 ,可执行任务项 = []
- time = 2 ,任务 1 进入任务队列,可执行任务项 = [1]
- time = 3 ,任务 2 进入任务队列,可执行任务项 = [1, 2]
- 同样在 time = 3 ,CPU 完成任务 0 并开始执行队列中用时最短的任务 2 ,可执行任务项 = {1]
- time = 4 ,任务 3 进入任务队列,可执行任务项 = [1, 3]
- time = 5 ,CPU 完成任务 2 并开始执行队列中用时最短的任务 3 ,可执行任务项 = {1]
- time = 6 ,CPU 完成任务 3 并开始执行任务 1 ,可执行任务项 = []
- time = 10 ,CPU 完成任务 1 并进入空闲状态
分析
这里,我们维护一个
-
进入任务队列的时刻
; -
执行时长
; -
任务编号
。
由于 python
是小根堆,我们需要实现该对象的 def __lt__(self, other)
方法。
未完待续。。。
代码实现
class Task(object): def __init__(self, enqueue_time, processing_time, index): self.enqueue_time = enqueue_time self.processing_time = processing_time self.index = index def __lt__(self, other): """ 使用<排序时,会被调用 """ # 如果任务具有相同的执行时间,则比较下标 if self.processing_time == other.processing_time: return self.index < other.index # 否则返回执行时间最短的任务 else: return self.processing_time < other.processing_time class Solution: def getOrder(self, tasks: List[List[int]]) -> List[int]: n = len(tasks) # 将所有的任务按照入队时刻排序 _tasks = list() for index, task in enumerate(tasks): _tasks.append(Task(task[0], task[1], index)) _tasks.sort(key=lambda x: x.enqueue_time) result = list() queue = list() # 使用优先级队列来保存所有的等待执行的任务 current_time = 0 # 用于记录CPU执行的时刻 pointer = 0 # 标记已经遍历过的任务数量 for i in range(n): # 如果堆为空,则当前时刻就是下一个待处理的任务入队时刻 if not queue: current_time = max(current_time, _tasks[pointer].enqueue_time) # 将入队时间小于当前时刻的所有任务先放入堆中,并记录遍历过的任务数量 while pointer < n and _tasks[pointer].enqueue_time <= current_time: # 任务放入堆中,Python是小根堆,排序会使用"<"符号,需要重载"__lt__"方法 heapq.heappush(queue, _tasks[pointer]) pointer += 1 # 从堆中取出一个任务来执行 task = heapq.heappop(queue) # 将执行过的任务的序号记录下来 result.append(task.index) # 当前时刻向后偏移任务执行的时长 current_time += task.processing_time return result
应用2:Leetcode 621. 任务调度器
题目
给你一个用字符数组
tasks
表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。
然而,两个 相同种类 的任务之间必须有长度为整数n
的冷却时间,因此至少有连续n
个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的 最短时间 。
示例 1:
输入:
tasks = ["A","A","A","A","A","A","B","C","D","E","F","G"]
,n = 2
输出:16
解释:一种可能的解决方案是:A -> B -> C -> A -> D -> E -> A -> F -> G -> A -> (待命) -> (待命) -> A -> (待命) -> (待命) -> A
分析
比较朴素的想法是,我们按照时间顺序,依次给每一个时间单位分配任务。
那么如果当前有多种任务不在冷却中,那么我们应该如何挑选执行的任务呢?直觉上,我们应当选择剩余执行次数最多的那个任务,将每种任务的剩余执行次数尽可能平均,使得 CPU 处于待命状态的时间尽可能少。
我们使用二元组
同时,我们维护一个列表
那么,初始状态时,所有的任务都可以在第一个时刻执行,因此,将所有的
我们使用
算法步骤:
-
统计每类任务出现的次数;
-
初始化每类任务的下一个可以执行的时刻及其剩余可执行次数;
初始状态,每类任务的下一个可以执行的时刻都是
。 -
将时刻
初始化为 ; -
遍历所有的任务,对于每一个待执行的任务:
-
首先,将时刻
加 ; -
然后,跳过 CPU 空转的时间段,计算CPU空转的时间方法:
-
遍历所有的任务种类,找到剩余可执行次数大于
的所有类型的任务中,下一个可执行时刻最小的时间 ; -
如果
大于 ,则说明存在冷却时间,可以直接将时间 time 移动到 ,从而跳过 CPU 冷却的时段。
-
-
找到下一个最优的任务,查找方法如下:
-
遍历所有的
-
最优的任务需要满足的条件:
-
该类任务的剩余可执行次数大于 0 ,并且下一个可执行时刻小于当前时刻
,否则,这个任务就是处于冷却中的; -
该类任务的剩余可执行次数是最多的。
-
-
更新该类任务的下一个可执行的时刻,即
; -
同时,该类任务任务的剩余可执行次数减
;
-
-
代码实现
from typing import List from collections import Counter class Solution: def leastInterval(self, tasks: List[str], n: int) -> int: frequency = Counter(tasks) task_category = list() for _rest in frequency.values(): task_category.append([1, _rest]) time = 0 for i in range(len(tasks)): time += 1 # 跳过CPU空转的时间 _next_valid = list() for _task in task_category: if _task[1] > 0: _next_valid.append(_task[0]) time = max(time, min(_next_valid)) # 找到下一个最优任务 best = -1 for j, _task in enumerate(task_category): if _task[1] and _task[0] <= time: if best == -1 or _task[1] > task_category[best][1]: best = j # 下一次执行时刻:当前时刻+冷却时间+1 task_category[best][0] = time + n + 1 task_category[best][1] -= 1 return time
参考:
本文作者:LARRY1024
本文链接:https://www.cnblogs.com/larry1024/p/17482786.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步