Skip to content
AI360Xpert
Back to System-Design-Adjacent / OOP Coding
Medium

Design Hit Counter

Design a hit counter which counts the number of hits received in the past 5 minutes (i.e., the past 300 seconds). Your system should accept a timestamp parameter (in seconds granularity), and you may assume that calls are being made to the system in chronological order (i.e., timestamp is monotonically increasing). Several hits may arrive roughly at the same time. Implement the `HitCounter` class: - `HitCounter()` Initializes the object of the hit counter system. - `void hit(int timestamp)` Records a hit that happened at `timestamp` (in seconds). Several hits may happen at the same `timestamp`. - `int getHits(int timestamp)` Returns the number of hits in the past 5 minutes from `timestamp` (i.e., the past 300 seconds).

Examples

Input:["HitCounter", "hit", "hit", "hit", "getHits", "hit", "getHits", "getHits"] [[], [1], [2], [3], [4], [300], [300], [301]]
Output:[null, null, null, null, 3, null, 4, 3]
HitCounter hitCounter = new HitCounter(); hitCounter.hit(1); // hit at timestamp 1. hitCounter.hit(2); // hit at timestamp 2. hitCounter.hit(3); // hit at timestamp 3. hitCounter.getHits(4); // get hits at timestamp 4, return 3. hitCounter.hit(300); // hit at timestamp 300. hitCounter.getHits(300); // get hits at timestamp 300, return 4. hitCounter.getHits(301); // get hits at timestamp 301, return 3.

Constraints

  • 1 <= timestamp <= 2 * 10^9
  • All the calls are being made to the system in chronological order (i.e., timestamp is monotonically increasing).
  • At most 300 calls will be made to hit and getHits.

Optimal Solution

Approach

Since we only care about hits in the last 300 seconds, we don't need to store all hits indefinitely. We can keep track of hits using a fixed-size array or a queue. **Approach using a queue (or double-ended queue)** 1. **Queue**: Store the timestamps of the hits in a queue. 2. **Hit Operation**: Simply enqueue the incoming timestamp. Since timestamps are monotonically increasing, the queue is naturally sorted. 3. **GetHits Operation**: Before returning the size of the queue, we remove all elements from the front of the queue that are outside the 300-second window (i.e., `timestamp - front_timestamp >= 300`). The remaining elements in the queue are all within the valid window, so we just return the queue's size. **Optimized Approach (Buckets)** If the number of hits per second is very large, storing each timestamp individually uses too much space. Instead, we can use two arrays of size 300: - `times`: Stores the timestamp mapped to a specific bucket (`timestamp % 300`). - `hits`: Stores the count of hits for that timestamp. When recording a hit, we find the bucket `idx = timestamp % 300`. If `times[idx]` doesn't match the current `timestamp`, it means it's from an older 5-minute window, so we update `times[idx] = timestamp` and reset `hits[idx] = 1`. If it matches, we simply increment `hits[idx]`. When getting hits, we iterate over all 300 buckets and sum the `hits` where `timestamp - times[i] < 300`. This approach strictly uses O(300) = O(1) space and time.

Complexity Analysis

Time Complexity
O(1)
Space Complexity
O(N)
Solution.java
class HitCounter {    private int[] times;    private int[] hits;
    public HitCounter() {        times = new int[300];        hits = new int[300];    }        public void hit(int timestamp) {        int idx = timestamp % 300;        if (times[idx] != timestamp) {            times[idx] = timestamp;            hits[idx] = 1;        } else {            hits[idx]++;        }    }        public int getHits(int timestamp) {        int total = 0;        for (int i = 0; i < 300; i++) {            if (timestamp - times[i] < 300) {                total += hits[i];            }        }        return total;    }}