周賽309。相似題1606. find servers that handled most number of requests。沒有排序吃一個WA,好慘。

題目

輸入整數n,代表有n個房間,編號從0~n-1。
輸入二維整數陣列meeting,其中meeting[i] = [starti, endi],表示會議在左閉右開區間[starti, endi)舉行。所有starti的值都是唯一的。

依照以下規則分配會議室:

  • 優先使用編號最小的空房
  • 如果沒有可用的房間,會議要延遲到有房間空出才舉行,但是持續時間與原本相同
  • 若有多個被延遲的會議,由原定時間最早的會議優先舉行

求舉行最多次會議的房間號碼,若有多個房間相同,則回傳編號較小者。
左閉右開區間[a, b)指的是包含a~b-1的區間。

解法

這題要處理的細節雖然比較多,但是分開處理都不算太難。

  • 優先使用編號小的空房,可以用min heap
  • 占用的房要依結束時間順序彈出,也是min heap
  • 被延遲的會議,依原定時間順序執行,要排序
  • 被延遲的會議,持續時間不變,要求出會議持續時間

首先將meetings排序,將原本的(開始, 結束)轉換成(開始, 持續時間)。
而一開始所有房間都是空的,所以將0~n-1的房間放入最小堆疊heap中;反之busy初始為空。
還需要一個陣列cnt計算房間使用計數,還有變數time維護當前時間。

開始模擬開會排隊過程,遍歷排序好的會議:

  • 將時間time更新到會議開始時間
  • 如果沒有空房,也沒有結束的會議,則將時間快進到第一個會議結束時間
  • 開始釋放已經結束的會議,把房間放回free
  • 選擇號碼最小的空房,計數+1,算出結束時間丟進busy

最後從cnt找出使用最多次的房間就好。

房間n最多100,會議m最多500000。每個會議進出heap共2*m次,每次複雜度O(log m)。會議室總共也會進出共2*m次,每次複雜度(log n)。
加上排序會議的O(m log m),還有轉換會議時間的O(m),整體複雜度O(m log m)+O(m)+O(m log(n+m)),應該可以簡化成O(m log m)。

class Solution:
    def mostBooked(self, n: int, meetings: List[List[int]]) -> int:
        meetings.sort()
        mts=[[s,e-s]for s,e in meetings]
        cnt=[0]*n
        free=[]
        busy=[] # [end, room_id]
        time=0

        for i in range(n):
            heappush(free,i)
        
        for start,cost in mts:
            time=max(time,start)
            if not free and busy[0][0]>time:
                time=busy[0][0]
            # release finished room
            while busy and time>=busy[0][0]:
                ok_room=heappop(busy)[1]
                heappush(free,ok_room)
            # add room
            go_room=heappop(free)
            heappush(busy,[time+cost,go_room])
            cnt[go_room]+=1
            
        ans=None
        mx=-inf
        
        for i,n in enumerate(cnt):
            if n>mx:
                mx=n
                ans=i
                
        return ans