Sliding-Window API Rate Limiter
Reported by candidates from Patreon's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
The rule that trips people up in Patreon's rate limiter question is the expiry line: a request accepted at time 0 is gone by time 1000, not 1001. Patreon's OA, reported October 2026, hands you a limit, a sorted list of millisecond timestamps, and asks for one boolean per request. It's a sliding-window problem wearing an API costume. The logic is short, but the boundary and the rejected-request rule decide whether you pass. If you blank mid-assessment, StealthCoder runs invisibly on your desktop and gives you the working solution in real time. Know the shape before you sit down.
The problem
An in-memory rate limiter permits at most limit accepted requests in the rolling one-second window ending at each request timestamp. Timestamps are integer milliseconds in nondecreasing order. Before deciding a request at time t, discard accepted requests with timestamp at most t - 1000. Accept the current request when fewer than limit accepted timestamps remain. Rejected requests do not consume capacity. Return one decision per request. Function allowRequests(limit: int, timestamps: int[]) → boolean[] Examples Example 1 limit = 3 timestamps = [0,100,200,300,1000,1001] return = [true,true,true,false,true,false] The fourth request is rejected. At time 1000, the accepted request at time 0 expires, so the fifth request is accepted. At time 1001, three accepted requests remain in the rolling window, so the sixth is rejected. Example 2 limit = 1 timestamps = [5,5,1004,1005] return = [true,false,false,true] The rejected duplicate at time 5 does not consume capacity; the accepted request expires only when the timestamp reaches 1005. Constraints 1 <= limit <= 10^5. 1 <= timestamps.length <= 10^5. 0 <= timestamps[i] <= 2^31 - 1. Timestamps are nondecreasing.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Keep a queue of accepted timestamps only. For each request at time t, pop from the front while the front is at most t - 1000. Then if the queue size is below limit, push t and output true. Otherwise output false and push nothing. That's it. Each timestamp enters and leaves the queue once, so it's O(n) total. The pitfalls are all in the details. Using less-than instead of less-than-or-equal on the expiry check breaks Example 1 at time 1000. Pushing rejected requests into the queue breaks Example 2, where the duplicate at time 5 must not consume capacity. Don't rebuild the window from scratch per request, because 10^5 requests with a naive scan is wasteful. A plain array with a head index works as well as a deque. If the boundary logic slips under pressure, StealthCoder is the safety net during the live OA.
StealthCoder is the hedge for the one pattern you didn't drill. It runs invisibly during the screen share.
You can drill Sliding-Window API Rate Limiter cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. If you're reading this with an OA window open, you're who this was built for.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Patreon's OA.
Patreon reuses patterns across OAs. If you're reading this with an OA window open, you're who this was built for. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Sliding-Window API Rate Limiter FAQ
What's the trick in the Patreon sliding-window rate limiter?+
Store only accepted timestamps in a queue. Before each decision, evict from the front anything at or below t - 1000. Accept if the queue holds fewer than limit entries, then push. Rejected requests never get stored. Every element is added and removed at most once.
Is the expiry boundary inclusive or exclusive?+
Requests with timestamp at most t - 1000 are discarded. So a request at time 0 is gone at time 1000. Example 1 confirms it: the fifth request at 1000 is accepted because the one at 0 expired. Use the less-than-or-equal comparison.
Do rejected requests count toward the limit?+
No. Rejected requests do not consume capacity, so never push them onto the queue. Example 2 shows it: with limit 1, the duplicate at time 5 is rejected, and the request at 1005 is accepted once the original at 5 expires.
What's the time complexity and does it fit the constraints?+
O(n) time and O(min(n, limit)) space using a queue or an array with a head pointer. With up to 10^5 timestamps, that's comfortable. A solution that rescans all previous accepted requests per call risks being too slow.
How do I prepare for this in 48 hours?+
Write the queue version once from memory and run both examples by hand. Then test edge cases: duplicate timestamps, limit equal to 1, and a gap of exactly 1000 ms. Make sure you can explain why eviction happens before the capacity check. That covers most of what this question tests.