雙周賽107。聽說時間限制給很緊,10^6會被卡掉,有點機車。

題目

輸入整數n,代表伺服器的數量。輸入二維整數陣列logs,其中logs[i] = [server_id, time],代表伺服器server_id在時間點time收到一次請求。

還輸入一個整數x,和整數陣列queries。

回傳和queries相同長度的整數陣列arr,其中arr[i]代表在區間[queries[i]-x, queries[i]]沒有收到任何請求的伺服器數量。

解法

對於每個查詢q,要找的是[q-x, q]區間沒有收到請求的伺服器,馬上就想到滑動框口
枚舉每個時間點q作為滑動窗口的右端點,q-x作為左端點,維護這個區間內各個伺服器收到的請求數量。

要維護無請求伺服器比較麻煩,需要兩個雜湊表,一個計請求數,一個裝無請求的編號;反過來想,既然知道伺服器總共有n個,那麼只用一個雜湊表freq計請求數就好,在雜湊表內出現過的就是有請求伺服器,用n減掉freq的大小就是無請求數量。

因為quries是無序的,先以查詢值q將查詢id分組,以遞增順序遍歷所有查詢q,將窗口移動到適當位置後才把對應的id填上答案。

瓶頸在於排序,時間複雜度O(M log M + Q log Q),其中M為logs大小,Q為查詢次數。
空間複雜度O(n + Q)。

class Solution:
    def countServers(self, n: int, logs: List[List[int]], x: int, queries: List[int]) -> List[int]:
        N=len(logs)
        Q=len(queries)
        ans=[0]*Q
        qid_group=defaultdict(list)
        for qid,qtime in enumerate(queries): # sort qid by query time
            qid_group[qtime].append(qid)

        logs.sort(key=itemgetter(1)) # sort logs by time
        freq=Counter()
        left=0
        right=0
        for qtime in sorted(qid_group):
            while right<N and logs[right][1]<=qtime: # expand window
                freq[logs[right][0]]+=1
                right+=1
                    
            while left<N and logs[left][1]<qtime-x: # shrink window
                freq[logs[left][0]]-=1
                if freq[logs[left][0]]==0: # delete key with frequency 0 
                    del freq[logs[left][0]]
                left+=1

            for qid in qid_group[qtime]: # answer queries
                ans[qid]=n-len(freq)
            
        return ans

其實也不用將queries分組處理,只要將查詢時間和查詢id一起排序,直接遍歷就可以。

class Solution:
    def countServers(self, n: int, logs: List[List[int]], x: int, queries: List[int]) -> List[int]:
        N=len(logs)
        Q=len(queries)
        ans=[0]*Q
        qid_group=defaultdict(list)
        qs=[[qtime,qid]for qid,qtime in enumerate(queries)]
        qs.sort(key=itemgetter(0)) # sort queries by qtime
        logs.sort(key=itemgetter(1)) # sort logs by time
        
        freq=Counter()
        left=0
        right=0
        for qtime,qid in qs:
            while right<N and logs[right][1]<=qtime: # expand window
                freq[logs[right][0]]+=1
                right+=1
                    
            while left<N and logs[left][1]<qtime-x: # shrink window
                freq[logs[left][0]]-=1
                if freq[logs[left][0]]==0: # delete key with frequency 0 
                    del freq[logs[left][0]]
                left+=1
                
            ans[qid]=n-len(freq) # answer queries
            
        return ans