解題說明
Number of Recent Calls
題目描述:設計一個 RecentCounter 類別,ping(t) 方法記錄時間點 t 的一次請求,並回傳在 [t-3000, t] 範圍內的請求總數(保證每次 t 嚴格遞增)。
解題思路:使用佇列(queue)儲存所有請求時間。每次 ping(t) 時,先將 t 加入佇列尾端,再從佇列前端移除所有早於 t-3000 的舊請求。由於 t 嚴格遞增,佇列天然維持有序狀態,只需從前端逐一彈出過期時間點即可。最終佇列的大小就是 [t-3000, t] 範圍內的請求數。此題是滑動視窗(sliding window)概念的經典應用。
C++ 解法
複雜度分析
時間複雜度:每次 ping 均攤 O(1) — 每個時間點最多被加入和移除佇列各一次;最壞單次 O(n) 但總體均攤 O(1)。
空間複雜度:O(W) — 佇列中最多保存寬度 W=3000 毫秒內的請求數。
虛擬碼
1. Initialize empty queue q
2. ping(t):
a. Push t to back of q
b. While q.front() < t - 3000:
- Pop front of q
c. Return size of q其他解法
定長陣列 + 循環索引:由於時間窗口固定為 3000ms,可用大小 3001 的循環陣列取代佇列,以 t % 3001 為索引存計數。但此法僅適用於固定視窗大小且時間為整數的場景。
有序集合 / 二分搜尋:用有序集合儲存所有請求時間,每次用二分搜尋找出 t-3000 的位置。時間複雜度 O(log n),但比佇列方案複雜,不必要。
延伸思考
- 若時間窗口不是固定的 3000ms 而是動態指定,設計上需要做哪些調整?
- 如何修改此設計以同時支援查詢任意過去時間區間
[a, b]內的請求數? - 在高並發多執行緒環境中,此佇列設計需要做哪些同步保護?