621. Task Scheduler
MediumDescription
給定一個字元陣列
tasks(代表 CPU 要執行的任務)和冷卻間隔n。相同任務之間必須間隔至少n個時間單位。CPU 可以執行不同任務或閒置。求完成所有任務需要的最少時間單位。
Example:
Input: tasks = [“A”,“A”,“A”,“B”,“B”,“B”], n = 2 Output: 8
Intuition#
核心思路:頻率最高的任務決定了最少時間的下界,用 Max Heap + Queue 貪心排程。
- 頻率最高的任務之間必須間隔 n,形成 (maxFreq - 1) 個間隔
- 每個間隔大小為 n + 1(包含任務本身),用其他任務填滿間隔
- 貪心策略:優先排頻率最高的任務,用 Max Heap 確保每次選最高頻的
Approaches#
1: Math / Greedy 公式法#
- 概念: 最少時間 = max(任務總數, (maxFreq - 1) * (n + 1) + maxCount),其中 maxCount 是頻率等於 maxFreq 的任務數
- 時間複雜度:
O(n)- n 為任務數 - 空間複雜度:
O(1)- 最多 26 個字母
class Solution {
fun leastInterval(tasks: CharArray, n: Int): Int {
val freq = IntArray(26)
for (task in tasks) freq[task - 'A']++
val maxFreq = freq.max()
val maxCount = freq.count { it == maxFreq }
return maxOf(tasks.size, (maxFreq - 1) * (n + 1) + maxCount)
}
}⭐2: Max Heap + Queue 模擬#
- 概念: 用 Max Heap 存各任務剩餘次數,每個時間單位取出頻率最高的執行。已執行的任務加入等待佇列,冷卻結束後再放回 Heap
- 時間複雜度:
O(m * n)- m 為任務總數(最壞情況每個任務都需等待) - 空間複雜度:
O(1)- 最多 26 個任務種類
class Solution {
fun leastInterval(tasks: CharArray, n: Int): Int {
val freq = IntArray(26)
for (task in tasks) freq[task - 'A']++
val maxHeap = PriorityQueue<Int>(compareByDescending { it })
for (f in freq) {
if (f > 0) maxHeap.offer(f)
}
var time = 0
val queue: ArrayDeque<Pair<Int, Int>> = ArrayDeque() // (remaining count, available time)
while (maxHeap.isNotEmpty() || queue.isNotEmpty()) {
time++
if (maxHeap.isNotEmpty()) {
val cnt = maxHeap.poll() - 1
if (cnt > 0) {
queue.addLast(cnt to time + n)
}
}
if (queue.isNotEmpty() && queue.first().second == time) {
maxHeap.offer(queue.removeFirst().first)
}
}
return time
}
}🔑 Takeaways#
- Pattern: 排程問題常見 Heap + 冷卻佇列的組合
- 關鍵技巧: 公式法更快但需要推導;Heap 模擬法更直觀且容易推廣到變體題;理解「最高頻任務決定下界」是關鍵