Description
給定
servers陣列(每個伺服器的權重)和tasks陣列(每個任務的處理時間)。第 j 個任務在時間 j 到達。分配規則:優先選權重最小的空閒伺服器(權重相同選 index 小的)。若無空閒則等待。回傳每個任務被分配到的伺服器 index。
Example:
Input: servers = [3,3,2], tasks = [1,2,3,2,1,2] Output: [2,2,0,2,1,2]
Intuition#
核心思路:用兩個 Heap 分別管理空閒伺服器和忙碌伺服器,模擬任務分配過程。
- 空閒 Heap (free):按 (weight, index) 排序
- 忙碌 Heap (busy):按 (完成時間, weight, index) 排序
- 每個時間點先把完成的伺服器移回 free,再分配任務
- 若沒有空閒伺服器,快轉到最近的伺服器完成時間
Approaches#
⭐1: 雙 Heap 模擬#
- 概念: free heap 管理可用伺服器,busy heap 管理正在工作的伺服器,按時間步進模擬
- 時間複雜度:
O((n + m) log m)- n 為任務數,m 為伺服器數 - 空間複雜度:
O(m + n)
class Solution {
fun assignTasks(servers: IntArray, tasks: IntArray): IntArray {
val m = servers.size
val n = tasks.size
// free: (weight, index)
val free = PriorityQueue<IntArray>(compareBy({ it[0] }, { it[1] }))
for (i in 0 until m) {
free.offer(intArrayOf(servers[i], i))
}
// busy: (finishTime, weight, index)
val busy = PriorityQueue<IntArray>(compareBy({ it[0] }, { it[1] }, { it[2] }))
val result = IntArray(n)
for (t in 0 until n) {
val time = t.toLong()
// 釋放已完成的伺服器
while (busy.isNotEmpty() && busy.peek()[0] <= time) {
val server = busy.poll()
free.offer(intArrayOf(server[1], server[2]))
}
if (free.isEmpty()) {
// 快轉到最近完成的伺服器
val earliest = busy.peek()[0].toLong()
while (busy.isNotEmpty() && busy.peek()[0].toLong() == earliest) {
val server = busy.poll()
free.offer(intArrayOf(server[1], server[2]))
}
val server = free.poll()
result[t] = server[1]
busy.offer(intArrayOf((earliest + tasks[t]).toInt(), servers[server[1]], server[1]))
} else {
val server = free.poll()
result[t] = server[1]
busy.offer(intArrayOf(t + tasks[t], servers[server[1]], server[1]))
}
}
return result
}
}🔑 Takeaways#
- Pattern: 雙 Heap 模式:一個管理可用資源,一個管理正在使用的資源
- 關鍵技巧: 當無可用資源時,快轉時間到最近的釋放時間;busy heap 的排序條件要包含 weight 和 index 以正確 tie-break