Medium草稿★★★★★O(n log n) 時間 · O(n) 空間
HeapPriority QueueSortingSimulation
Patterns⛰️ 堆・Top-K🎮 模擬🔢 排序後處理
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

1834Single Threaded CPUHeap / Priority QueueMediumHeap / Priority Queue

給定 tasks[i] = [enqueueTime, processingTime],表示第 i 個任務在 enqueueTime 可用,需要 processingTime 時間處理。CPU 單執行緒,同時可用的任務中選 processingTime 最小的先執行(相同則選 index 小的)。回傳 CPU 處理任務的順序。

Example:

Input: tasks = [[1,2],[2,4],[3,2],[4,1]] Output: [0,2,3,1]

Intuition

TIP

核心思路:模擬 CPU 排程,用 Min Heap 依 processingTime 排序可用任務,依時間順序處理。

Approaches

1. Brute-Force Simulation: Pick Shortest Task per Step — O(n²) / O(n)
  • Idea: 每輪線性掃所有未做、已可用的任務,挑處理時間最短(同則索引小)者;沒有可用就快轉時間
  • Time: O(n²) - n 輪、每輪掃描 O(n)
  • Space: O(n)
class Solution {
    fun getOrder(tasks: Array<IntArray>): IntArray {
        val n = tasks.size
        val done = BooleanArray(n)
        val result = IntArray(n)
        var time = 0L
        fun pick(): Int {
            var best = -1
            for (i in 0 until n) {
                if (done[i] || tasks[i][0] > time) continue
                if (best == -1 || tasks[i][1] < tasks[best][1] ||
                    (tasks[i][1] == tasks[best][1] && i < best)) best = i
            }
            return best
        }
        for (r in 0 until n) {
            var best = pick()
            if (best == -1) {                 // 沒有可用任務 → 快轉到最早 enqueue 時間
                var next = Long.MAX_VALUE
                for (i in 0 until n) if (!done[i]) next = minOf(next, tasks[i][0].toLong())
                time = next
                best = pick()
            }
            done[best] = true
            result[r] = best
            time += tasks[best][1]
        }
        return result
    }
}
⭐ 2. Sorting + Min-Heap Simulation — O(n log n) / O(n)
  • Idea: 依時間排序任務,用 Min Heap 管理可用任務佇列,模擬 CPU 執行流程
  • Time: O(n log n) - 排序 + heap 操作
  • Space: O(n)
class Solution {
    fun getOrder(tasks: Array<IntArray>): IntArray {
        val n = tasks.size
        val indexed = Array(n) { intArrayOf(tasks[it][0], tasks[it][1], it) }
        indexed.sortBy { it[0] }

        // Min Heap: (processingTime, originalIndex)
        val heap = PriorityQueue<IntArray>(compareBy({ it[1] }, { it[2] }))
        val result = IntArray(n)
        var time = 0L
        var i = 0
        var ri = 0

        while (ri < n) {
            // 若 heap 為空且還有任務,快轉時間
            if (heap.isEmpty() && i < n && time < indexed[i][0]) {
                time = indexed[i][0].toLong()
            }

            // 加入所有在 time 之前(含)可用的任務
            while (i < n && indexed[i][0] <= time) {
                heap.offer(indexed[i])
                i++
            }

            // 執行最優先的任務
            val task = heap.poll()
            result[ri++] = task[2]
            time += task[1]
        }

        return result
    }
}

🔑 Takeaways