AO
Back

Rate Limiter (Sliding Window)

CodingPhone, OnsiteSoftware Engineer, Machine Learning EngineerLast reported July 2026High Frequency

Problem Overview

The round is two graded parts, each with a given signature and its own test cases.

Full problem statement

The round is two graded parts, each with a given signature and its own test cases. Reported follow-ups extend it further (arbitrary fields, per-IP, garbage collection) but those are discussed rather than submitted.

Level 1 — Global Rate Limiter

Implement a rate limiter that processes a sorted list of request timestamps and returns a boolean list indicating whether each request should be allowed or denied.

def rate_limiter(
    requestTimestamps: list[int],  # sorted list of request timestamps
    windowLength: int,              # length of the sliding time window
    maxRequests: int                # max requests allowed within the window
) -> list[bool]:

For each request at timestamp t, count how many already-allowed requests fall within the window (t - windowLength, t]. If that count is already maxRequests, deny the current request (return False); otherwise allow it (return True) and record it.

Example:

  • Input: requestTimestamps=[1,2,3,4,5,6], windowLength=3, maxRequests=2
  • Output: [True, True, False, True, True, False]
  • Explanation: t=1 allowed (0 in window); t=2 allowed (1 in window); t=3 denied (2 already: t=1,t=2); t=4 allowed (t=1 expired, only t=2 inside → 1); t=5 allowed (t=4 only → 1); t=6 denied (t=4,t=5 → 2).

Level 2 — Per-Entity Rate Limiter (Follow-up)

Extend the rate limiter to enforce independent sliding-window limits per userId AND per experienceId. A request is denied if either the per-user limit or the per-experience limit is exceeded.

def per_entity_rate_limiter(
    requestTimestamps: list[int],
    userIds: list[int],
    experienceIds: list[str],
    windowLength: int,
    maxRequests: int
) -> list[bool]:

Example:

  • Input: requestTimestamps=[1,2,3,4,5], userIds=[1,1,2,1,2], experienceIds=["A","A","A","A","B"], windowLength=3, maxRequests=1
  • Output: [True, False, False, True, True]
  • Explanation: t=1 (u=1,exp=A): allowed. t=2 (u=1,exp=A): user 1 already has 1 → deny. t=3 (u=2,exp=A): exp A already has 1 (at t=1) → deny. t=4 (u=1,exp=A): t=1 expired for both user 1 and exp A → allow. t=5 (u=2,exp=B): user 2's t=3 expired, exp B is new → allow.

Only allowed requests should be recorded in the per-entity queues (i.e., denied requests do not count against future limits).

Follow-up Arc

Interviewers escalate through these phases. The order varies, but most candidates see at least one from each bucket.
Edge cases · 3Trade-off discussion · 2
Edge cases

Now extend to rate limit independently per userId AND per experienceId. A request is denied if either constraint is violated.

Probes for: After Level 1 is solved correctly

What if a request has many arbitrary fields (not just userId and experienceId) that each need independent rate limiting?

Probes for: After Level 2 is solved

Extend to per-IP rate limiting instead of (or in addition to) userId/experienceId. (when: After Level 2 (variant))

Trade-off discussion

What is the time and space complexity of your solution?

Probes for: After solving either level

How would you handle garbage collection of stale entries (entities that haven't had requests in a long time)?

Probes for: After discussion of basic implementation

Approach Trade-offs

Approaches actually attempted in reports — including ones that lost candidates time. Pick deliberately.
ApproachNotes
Sets / sorted containers per entityOne variant mentioned using sets; provides O(log n) insertion and range queries but more complex than a simple deque; useful if timestamps are not necessarily sorted.
Token bucket / fixed window counterSimpler to implement but less accurate—fixed windows can allow burst at window boundaries; sliding window is the canonical ask here.

What Reports Emphasize

Common mistakes: Not correctly handling the condition for evicting stale timestamps from the deque — the boundary check (strict vs. inclusive) was the most common source of wrong answers on hidden test cases.; Spending too much time on Level 1 (compile errors, debugging brackets, typos) and then running out of time to finish Level 2, causing a fail.; Writing a main() function or extra boilerplate before realizing only the function body needed to be submitted, wasting significant time.; For Level 2, not correctly maintaining both the user deque and the experience deque — updating one but forgetting the other when a request is denied, leading to state corruption.

Interviewer hints: When a candidate got the window eviction logic wrong, the interviewer provided hints rather than letting them spin — but it still counted against them.; The interviewer noticed a typo bug in one candidate's code but the test cases were not thorough enough to catch it; the interviewer mentioned it explicitly after the fact.; After Level 2, the interviewer asked about time and space complexity.; The platform has both visible and hidden test cases; hidden cases are not shown even if they fail, so candidates could not see what they missed.

What passers do: Used a deque (queue) for Level 1 and a dict of deques for Level 2, which is the canonical solution the interviewers expected.; Passed even with hidden test cases not fully covered — interviewers weigh approach and communication heavily, not just perfect output.; Finished Level 1 quickly and moved on to Level 2; candidates who spent too long on Level 1 ran out of time on Level 2 and failed.; Caught their own bugs (typos, off-by-one in window boundary) before the interviewer flagged them, or found discrepancies in the system's own solution.

Practice

Write your own against 10 test cases, or read the worked solution — approach, complexity, and code that runs.

More Roblox Questions

Free preview

Every question in the Roblox catalog gets this depth

What you just read — canonical solution, follow-up arc, what passing candidates actually did — exists for all 34 Roblox questions, refreshed monthly from new candidate reports.

$59/mo — or $50/mo with the 3-month pass · cancel anytime
Roblox · Coding · Reported 29× across candidate reports
Is this helpful?