Description

給定 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#

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

  • 這是一個事件驅動的模擬題
  • 先依 enqueueTime 排序,方便依時間加入任務
  • 用 Min Heap 維護目前可用的任務,按 (processingTime, index) 排序
  • 當 heap 為空但還有任務時,快轉到下一個任務的 enqueueTime

Approaches#

⭐1: Sorting + Min Heap 模擬#

  • 概念: 依時間排序任務,用 Min Heap 管理可用任務佇列,模擬 CPU 執行流程
  • 時間複雜度: O(n log n) - 排序 + heap 操作
  • 空間複雜度: 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#

  • Pattern: 事件驅動模擬 + Priority Queue 排程
  • 關鍵技巧: 需要保留原始 index 用於輸出和 tie-breaking;當 heap 為空時要快轉時間避免無限迴圈;注意使用 Long 避免時間溢位