621. Task Scheduler 任务调度器
給你一個(gè)用字符數(shù)組?tasks 表示的 CPU 需要執(zhí)行的任務(wù)列表。其中每個(gè)字母表示一種不同種類(lèi)的任務(wù)。任務(wù)可以以任意順序執(zhí)行,并且每個(gè)任務(wù)都可以在 1 個(gè)單位時(shí)間內(nèi)執(zhí)行完。在任何一個(gè)單位時(shí)間,CPU 可以完成一個(gè)任務(wù),或者處于待命狀態(tài)。
然而,兩個(gè) 相同種類(lèi) 的任務(wù)之間必須有長(zhǎng)度為整數(shù) n 的冷卻時(shí)間,因此至少有連續(xù) n 個(gè)單位時(shí)間內(nèi) CPU 在執(zhí)行不同的任務(wù),或者在待命狀態(tài)。
你需要計(jì)算完成所有任務(wù)所需要的 最短時(shí)間 。
?
示例 1:
輸入:tasks = ["A","A","A","B","B","B"], n = 2 輸出:8 解釋:A -> B -> (待命) -> A -> B -> (待命) -> A -> B在本示例中,兩個(gè)相同類(lèi)型任務(wù)之間必須間隔長(zhǎng)度為 n = 2 的冷卻時(shí)間,而執(zhí)行一個(gè)任務(wù)只需要一個(gè)單位時(shí)間,所以中間出現(xiàn)了(待命)狀態(tài)。示例 2:
輸入:tasks = ["A","A","A","B","B","B"], n = 0 輸出:6 解釋:在這種情況下,任何大小為 6 的排列都可以滿足要求,因?yàn)?n = 0 ["A","A","A","B","B","B"] ["A","B","A","B","A","B"] ["B","B","B","A","A","A"] ... 諸如此類(lèi)示例 3:
輸入: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?
提示:
- 1 <= task.length <= 104
- tasks[i] 是大寫(xiě)英文字母
- n 的取值范圍為 [0, 100]
構(gòu)造
我們首先考慮所有任務(wù)種類(lèi)中執(zhí)行次數(shù)最多的那一種,記它為 A\texttt{A}A,的執(zhí)行次數(shù)為 maxExec\textit{maxExec}maxExec。
我們使用一個(gè)寬為 n+1n+1n+1 的矩陣可視化地展現(xiàn)執(zhí)行 A\texttt{A}A 的時(shí)間點(diǎn)。其中任務(wù)以行優(yōu)先的順序執(zhí)行,沒(méi)有任務(wù)的格子對(duì)應(yīng) CPU 的待命狀態(tài)。由于冷卻時(shí)間為 nnn,因此我們將所有的 A\texttt{A}A 排布在矩陣的第一列,可以保證滿足題目要求,并且容易看出這是可以使得總時(shí)間最小的排布方法,對(duì)應(yīng)的總時(shí)間為:
(maxExec?1)(n+1)+1(\textit{maxExec} - 1)(n + 1) + 1 (maxExec?1)(n+1)+1
同理,如果還有其它也需要執(zhí)行 maxExec\textit{maxExec}maxExec 次的任務(wù),我們也需要將它們依次排布成列。例如,當(dāng)還有任務(wù) B\texttt{B}B 和 C\texttt{C}C 時(shí),我們需要將它們排布在矩陣的第二、三列。
如果需要執(zhí)行 maxExec\textit{maxExec}maxExec 次的任務(wù)的數(shù)量為 maxCount\textit{maxCount}maxCount,那么類(lèi)似地可以得到對(duì)應(yīng)的總時(shí)間為:
(maxExec?1)(n+1)+maxCount(\textit{maxExec} - 1)(n + 1) + \textit{maxCount} (maxExec?1)(n+1)+maxCount
讀者可能會(huì)對(duì)這個(gè)總時(shí)間產(chǎn)生疑問(wèn):如果 maxCount>n+1\textit{maxCount} > n+1maxCount>n+1,那么多出的任務(wù)會(huì)無(wú)法排布進(jìn)矩陣的某一列中,上面計(jì)算總時(shí)間的方法就不對(duì)了。我們把這個(gè)疑問(wèn)放在這里,先「假設(shè)」一定有 maxCount≤n+1\textit{maxCount} \leq n+1maxCount≤n+1。
處理完執(zhí)行次數(shù)為 maxExec\textit{maxExec}maxExec 次的任務(wù),剩余任務(wù)的執(zhí)行次數(shù)一定都小于 maxExec\textit{maxExec}maxExec,那么我們應(yīng)當(dāng)如何將它們放入矩陣中呢?一種構(gòu)造的方法是,我們從倒數(shù)第二列開(kāi)始,按照反向列優(yōu)先的順序(即先放入靠左側(cè)的列,同一列中先放入下方的行),依次放入每一種任務(wù),并且同一種任務(wù)需要連續(xù)地填入。例如還有任務(wù) D\texttt{D}D,E\texttt{E}E 和 F\texttt{F}F 時(shí),我們會(huì)按照下圖的方式依次放入這些任務(wù)。
對(duì)于任意一種任務(wù)而言,一定不會(huì)被放入同一行兩次(否則說(shuō)明該任務(wù)的執(zhí)行次數(shù)大于等于 maxExec\textit{maxExec}maxExec),并且由于我們是按照列優(yōu)先的順序放入這些任務(wù),因此任意兩個(gè)相鄰的任務(wù)之間要么間隔 nnn(例如上圖中位于同一列的相同任務(wù)),要么間隔 n+1n+1n+1(例如上圖中第一列和第二列的 F\texttt{F}F),都是滿足題目要求的。因此如果我們按照這樣的方法填入所有的任務(wù),那么就可以保證總時(shí)間不變,仍然為:
(maxExec?1)(n+1)+maxCount(\textit{maxExec} - 1)(n + 1) + \textit{maxCount} (maxExec?1)(n+1)+maxCount
當(dāng)然,這些都建立在我們的「假設(shè)」之上,即我們不會(huì)填「超出」n+1n+1n+1 列。但讀者可以想一想,如果我們真的填「超出」了 n+1n+1n+1 列,會(huì)發(fā)生什么呢?
上圖給出了一個(gè)例子,此時(shí) n+1=5n+1=5n+1=5 但我們填了 777 列。標(biāo)記為 X\texttt{X}X 的格子表示 CPU 的待命狀態(tài)。看上去我們需要 (5?1)×7+4=32(5-1) \times 7 + 4 = 32(5?1)×7+4=32 的時(shí)間來(lái)執(zhí)行所有任務(wù),但實(shí)際上如果我們填「超出」了 n+1n+1n+1 列,那么所有的 CPU 待命狀態(tài)都是可以省去的。這是因?yàn)?CPU 待命狀態(tài)本身只是為了規(guī)定任意兩個(gè)相鄰任務(wù)的執(zhí)行間隔至少為 nnn,但如果列數(shù)超過(guò)了 n+1n+1n+1,那么就算沒(méi)有這些待命狀態(tài),任意兩個(gè)相鄰任務(wù)的執(zhí)行間隔肯定也會(huì)至少為 nnn。此時(shí),總執(zhí)行時(shí)間就是任務(wù)的總數(shù) ∣task∣|\textit{task}|∣task∣。
同時(shí)我們可以發(fā)現(xiàn):
-
如果我們沒(méi)有填「超出」了 n+1n+1n+1 列,那么圖中存在 000 個(gè)或多個(gè)位置沒(méi)有放入任務(wù),由于位置數(shù)量為 (maxExec?1)(n+1)+maxCount(\textit{maxExec} - 1)(n + 1) + \textit{maxCount}(maxExec?1)(n+1)+maxCount,因此有:
∣task∣<(maxExec?1)(n+1)+maxCount|\textit{task}| < (\textit{maxExec} - 1)(n + 1) + \textit{maxCount} ∣task∣<(maxExec?1)(n+1)+maxCount
-
如果我們填「超出」了 n+1n+1n+1 列,那么同理有:
∣task∣>(maxExec?1)(n+1)+maxCount|\textit{task}| > (\textit{maxExec} - 1)(n + 1) + \textit{maxCount} ∣task∣>(maxExec?1)(n+1)+maxCount
因此,在任意的情況下,需要的最少時(shí)間就是 (maxExec?1)(n+1)+maxCount(\textit{maxExec} - 1)(n + 1) + \textit{maxCount}(maxExec?1)(n+1)+maxCount 和 ∣task∣|\textit{task}|∣task∣ 中的較大值。
Python
class Solution:def leastInterval(self, tasks: List[str], n: int) -> int:freq = collections.Counter(tasks)maxExec = max(freq.values())maxCount = sum(1 for v in freq.values() if v == maxExec)return max((maxExec - 1) * (n + 1) + maxCount, len(tasks))總結(jié)
以上是生活随笔為你收集整理的621. Task Scheduler 任务调度器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: JavaScript禁用鼠标右键菜单
- 下一篇: PyTorch报错No module n