Implement a sliding-window rate limiter
Company: Reddit
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This question evaluates a candidate's ability to implement a sliding-window rate limiter, emphasizing time-based algorithms, per-key state management, and efficient data-structure choices to achieve near-O(1) operations.
Constraints
- 1 <= limit <= 10^5
- 1 <= window <= 10^18
- 0 <= len(requests) <= 2 * 10^5
- For the same key, timestamps in the input are non-decreasing
- A denied request does not count toward future limits
Examples
Input: (3, 10, [('u1', 1), ('u1', 2), ('u1', 3), ('u1', 4), ('u1', 12)])
Expected Output: [True, True, True, False, True]
Explanation: The first three requests are allowed. At time 4, key 'u1' already has 3 allowed requests in the window (-6, 4], so it is denied. At time 12, the window is (2, 12], so timestamps 1 and 2 have expired and the request is allowed.
Input: (2, 3, [('a', 1), ('b', 1), ('a', 2), ('b', 2), ('a', 3), ('b', 4), ('a', 4)])
Expected Output: [True, True, True, True, False, True, True]
Explanation: Each key is limited independently. For 'a', requests at 1 and 2 are allowed, so the request at 3 is denied. At time 4 for 'a', timestamp 1 has expired because the window is (1, 4], so that request is allowed. Key 'b' follows the same logic independently.
Input: (3, 10, [])
Expected Output: []
Explanation: No requests means no decisions to return.
Input: (1, 1, [('x', 100), ('x', 100), ('x', 101), ('x', 101)])
Expected Output: [True, False, True, False]
Explanation: With limit 1 and window 1, only one allowed request can exist in (t - 1, t]. The second request at time 100 is denied. At time 101, the request from 100 has expired because 100 <= 101 - 1, so one request is allowed again; the next request at 101 is denied.
Solution
from collections import defaultdict, deque
def solution(limit, window, requests):
buckets = defaultdict(deque)
result = []
for key, timestamp in requests:
q = buckets[key]
cutoff = timestamp - window
while q and q[0] <= cutoff:
q.popleft()
if len(q) < limit:
q.append(timestamp)
result.append(True)
else:
result.append(False)
return resultTime complexity: O(r) total, amortized O(1) per request, where r is the number of requests. Space complexity: O(a), where a is the number of allowed timestamps currently stored across all keys.
Hints
- Use a hash map from key to a queue/deque of timestamps that were actually allowed for that key.
- Before checking a new request at time t, remove all timestamps <= t - window from that key's deque.