Skip to main content

359. Logger Rate Limiter

easyAsked at Uber

Design a logger that accepts messages once per 10 seconds — the LeetCode anchor for 'design a rate limiter' interview rounds. Uber asks this to test hash-map state, monotonic timestamps, and how you'd extend to per-key sliding windows.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Source citations

Public interview reports confirming this problem appears in Uber loops.

  • Glassdoor (2026-Q1)Uber backend onsite reports include 'design a rate limiter' rounds where LC 359 is the canonical anchor.
  • Blind (2025-11)Recurring in Uber API-platform interviews — extends naturally to sliding-window and token-bucket follow-ups.

Problem

Design a logger system that receives a stream of messages along with their timestamps. Each unique message should only be printed at most every 10 seconds (i.e., a message printed at timestamp t will prevent other identical messages from being printed until timestamp t + 10). Implement Logger: Logger() initializes the logger; shouldPrintMessage(timestamp, message) returns true if the message should be printed in the given timestamp, otherwise returns false.

Constraints

  • 0 <= timestamp <= 10^9
  • Every timestamp will be passed in non-decreasing order (chronological order).
  • 1 <= message.length <= 30
  • At most 10^4 calls will be made to shouldPrintMessage.

Examples

Example 1

Input
shouldPrintMessage(1,"foo"); shouldPrintMessage(2,"bar"); shouldPrintMessage(3,"foo"); shouldPrintMessage(8,"bar"); shouldPrintMessage(10,"foo"); shouldPrintMessage(11,"foo")
Output
[true,true,false,false,false,true]

Explanation: foo at t=1 (yes), bar at t=2 (yes), foo at t=3 (no, too soon), bar at t=8 (no, less than 10s), foo at t=10 (no, last was 1), foo at t=11 (yes, last allowed was 1 + 10 = 11).

Approaches

1. Hash map last-allowed-timestamp (optimal)

Store the next allowed timestamp per message. On a call, compare timestamp to the stored value.

Time
O(1) per call
Space
O(unique messages)
class Logger {
  constructor() { this.nextAllowed = new Map(); }
  shouldPrintMessage(timestamp, message) {
    const next = this.nextAllowed.get(message);
    if (next === undefined || timestamp >= next) {
      this.nextAllowed.set(message, timestamp + 10);
      return true;
    }
    return false;
  }
}

Tradeoff: O(1) per call, but memory grows with unique messages. Acceptable for typical workloads but unbounded for streams of unique messages.

2. Hash map with periodic cleanup

Same as above, but periodically sweep entries whose next-allowed time is in the past.

Time
Amortized O(1) per call
Space
Bounded by recent unique messages
class LoggerCleanup {
  constructor() { this.nextAllowed = new Map(); this.lastSweep = 0; }
  shouldPrintMessage(timestamp, message) {
    if (timestamp - this.lastSweep > 100) {
      for (const [k, v] of this.nextAllowed) {
        if (v <= timestamp) this.nextAllowed.delete(k);
      }
      this.lastSweep = timestamp;
    }
    const next = this.nextAllowed.get(message);
    if (next === undefined || timestamp >= next) {
      this.nextAllowed.set(message, timestamp + 10);
      return true;
    }
    return false;
  }
}

Tradeoff: Bounds memory growth for streams with many unique messages. Sweep cadence is a tradeoff between memory and amortized cost; tune to the workload.

3. Two-queue rolling buckets (variant)

Keep one queue per 10-second bucket. On call, pop expired buckets, then check if message is in current.

Time
Amortized O(1)
Space
O(active messages)
class LoggerBuckets {
  constructor() { this.recent = new Set(); this.previous = new Set(); this.bucketStart = 0; }
  shouldPrintMessage(timestamp, message) {
    if (timestamp - this.bucketStart >= 10) {
      this.previous = this.recent;
      this.recent = new Set();
      this.bucketStart = timestamp - (timestamp % 10);
    }
    if (this.recent.has(message) || this.previous.has(message)) return false;
    this.recent.add(message);
    return true;
  }
}

Tradeoff: Approximates a sliding window with two fixed buckets — same idea many production rate limiters use. Mention as the bridge to a real-world 'token bucket' or 'sliding-log' rate limiter follow-up.

Uber-specific tips

Uber interviewers grade this on the follow-ups, not the easy version. Expect them to ask: 'extend to per-user rate limit', 'extend to N requests per W seconds', 'distribute this across servers'. Have answers ready: per-user is keyed map, N-per-W is sliding-log or token bucket, distributed needs a shared store with monotonic timestamps.

Common mistakes

  • Storing the timestamp of the LAST print instead of the next ALLOWED — both work but the boundary off-by-one differs.
  • Forgetting that timestamps arrive in non-decreasing order — the problem guarantees it; don't add sorting.
  • Not addressing unbounded memory growth when asked about long-running logger.

Follow-up questions

An interviewer at Uber may pivot to one of these next:

  • Design a per-IP rate limiter, N requests per W seconds. (Sliding-log or token-bucket.)
  • What if timestamps could be out of order? (Need a sorted structure or sliding window with reordering.)
  • Distributed rate limiter — how would you share state across servers?

Solve it now

Free. No sign-up. Python and JavaScript run instantly in your browser.

Output

Press Run or Cmd+Enter to execute

FAQ

Why does this anchor a 'design a rate limiter' interview round?

LC 359 is the simplest rate-limit-style problem with a clean interface. Real interviews extend it to per-key sliding windows, token buckets, and distributed coordination — all built on the same hash-map foundation.

Is the cleanup variant necessary at the constraint scale?

Not for the 10^4 call bound — the basic map is fine. The cleanup version is what you mention when the interviewer asks 'what if this ran for years with unique messages?'.

Free learning resources

Curated free links for this problem.

Practice these live with InterviewChamp.AI

Drill Logger Rate Limiter and other Uber interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.

Practice these live with InterviewChamp.AI →