題目連結:
題目意譯:
你被給定兩個索引值從 0 開始之長度分別為 n 、 m 的整數陣列 servers 和 tasks 。 servers[i] 為第 i 個伺服器之權重,而 tasks[j] 代表處理第 j 個任務所需的秒數。
你現在正執行一個模擬系統,其將於所有任務處理完畢後關機。每個伺服器一次只能處理一個任務。你將可以處理第 j 個任務於第 j 秒,其開始於第 0 個任務於第 0 秒。為了處理任務 j ,你將其分配給空閒中權重最小的伺服器,且權重相同的情況下,將分配給索引值最小的伺服器。如果一個空閒的伺服器於第 t 秒時被分配到任務 j ,則它將會於第 t + tasks[j] 秒時再次變為空閒之狀態。
如果現在沒有空閒的伺服器,則你必須等到至少有一臺伺服器空閒為止,並且將閒置的任務越快處理掉越好。如果多個任務需被分配,則將它們依序以索引值遞增的方式分配。
你可以在同一秒內分配多個任務,如果該時刻有多個空閒的伺服器。
建立一個長度為 m 的陣列 ans ,其中 ans[j] 為第 j 個任務分配給的伺服器之索引值。
回傳陣列 ans 。
限制:
servers.length == n
tasks.length == m
1 ≦ n 、 m ≦ 2 × 10 ^ 5
1 ≦ servers[i] 、 tasks[j] ≦ 2 × 10 ^ 5
範例測資:
範例 1:
輸入: servers = [3,3,2], tasks = [1,2,3,2,1,2]
輸出: [2,2,0,2,1,2]
解釋: 事件時序如下:
- 在第 0 秒時,任務 0 被加入執行並在第 1 秒前處理於伺服器 2 。
- 在第 1 秒時,伺服器 2 變為空閒。任務 1 被加入執行並在第 3 秒前處理於伺服器 2 。
- 在第 2 秒時,任務 2 被加入執行並在第 5 秒前處理於伺服器 0 。
- 在第 3 秒時,伺服器 2 變為空閒。任務 3 被加入執行並在第 5 秒前處理於伺服器 2 。
- 在第 4 秒時,任務 4 被加入執行並在第 5 秒前處理於伺服器 1 。
- 在第 5 秒時,所有伺服器變為空閒。任務 5 被加入執行並在第 7 秒前處理於伺服器 2 。
範例 2:
輸入: servers = [5,1,4,3,2], tasks = [2,1,2,4,5,2,1]
輸出: [1,4,1,4,1,3,2]
解釋: 事件時序如下:
- 在第 0 秒時,任務 0 被加入執行並在第 2 秒前處理於伺服器 1 。
- 在第 1 秒時,任務 1 被加入執行並在第 2 秒前處理於伺服器 4 。
- 在第 2 秒時,伺服器 1 、 4 變為空閒。任務 2 被加入執行並在第 4 秒前處理於伺服器 1 。
- 在第 3 秒時,任務 3 被加入執行並在第 7 秒前處理於伺服器 4 。
- 在第 4 秒時,伺服器 1 變為空閒。任務 4 被加入執行並在第 9 秒前處理於伺服器 1 。
- 在第 5 秒時,任務 5 被加入執行並在第 7 秒前處理於伺服器 3 。
- 在第 6 秒時,任務 6 被加入執行並在第 7 秒前處理於伺服器 2 。
解題思維:
我們可以用兩個優先佇列(Priority Queue)available 、 schedule 以及一個變數 nowTime 來模擬整個系統之運作。其中 nowTime 代表現在的時間點、而 available 代表著當前可用的伺服器、 schedule 則代表著正在處理的工作(記得也存每個任務佔哪個伺服器,以便更新 available)。
因此 available 的頂端元素 available.top() 應為:權重最小的(若有多個權重一樣則為索引值最小的)伺服器、schedule 的頂端元素 schedule.top() 應為:預計結束時間點最小的任務。
首先,將 servers 的內容放入 available 中,以示一開始所有伺服器都是空閒的。
再來,掃過所有的任務 tasks[i]:
首先,我們先判斷 nowTime 是否 < i ,因為每個任務 i 是第 i 秒後才能執行,所以如果 nowTime 還沒跟上我們就需要更新(當然如果 nowTime 等於或甚至超過了 i 就不需要更新了)。
接著,我們判斷 available 是否為空(代表是否有無空閒伺服器給 tasks[i])。如果沒有,則我們需要等到一個最近(也可能多個最近)的任務結束,因此 nowTime 將更新成 schedule.top() 之結束時間點。
緊接著,我們將所有結束時間點 ≦ nowTime 的 schedule 中之任務給移除(schedule.pop(),除非 schedule 裡已經沒有任務了),並在每次 pop() 之前將 schedule.top() 之對應佔用伺服器放回到 available 中。
最後因為時間點對了、有空閒的伺服器、該結束的任務也結束了,因此我們便可以將 tasks[i] 賦予給 available.top() 那臺伺服器。而 tasks[i] 將結束於 nowTime + tasks[i] 。
其間所有 tasks[i] 之分配到的伺服器之索引值全數放入 ans 即可得到所求。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。