You have a RecentCounter
class which counts the number of recent requests within a certain time frame.
Implement the RecentCounter
class:
RecentCounter()
Initializes the counter with zero recent requests.int ping(int t)
Adds a new request at time t
, where t
represents some time in milliseconds, and returns the number of requests that has happened in the past 3000
milliseconds (including the new request). Specifically, return the number of requests that have happened in the inclusive range [t - 3000, t]
.It is guaranteed that every call to ping
uses a strictly larger value of t
than the previous call.
Example 1:
Input ["RecentCounter", "ping", "ping", "ping", "ping"] [[], [1], [100], [3001], [3002]] Output [null, 1, 2, 3, 3] Explanation RecentCounter recentCounter = new RecentCounter(); recentCounter.ping(1); // requests = [1], range is [-2999,1], return 1 recentCounter.ping(100); // requests = [1, 100], range is [-2900,100], return 2 recentCounter.ping(3001); // requests = [1, 100, 3001], range is [1,3001], return 3 recentCounter.ping(3002); // requests = [1, 100, 3001, 3002], range is [2,3002], return 3
Constraints:
1 <= t <= 109
ping
with strictly increasing values of t
.104
calls will be made to ping
.This problem requires designing a RecentCounter
class to count the number of recent requests within a 3000-millisecond window. Two approaches are presented: using a queue and using binary search.
This approach leverages a queue (deque
in Python, Queue
in Java, etc.) to efficiently track requests.
Algorithm:
__init__
(or constructor) initializes an empty queue.ping(t)
:
t
to the queue.t - 3000
, remove it from the queue. This maintains the 3000ms window.Time Complexity: O(N) in the worst case for ping()
, where N is the number of calls to ping()
. However, on average it's O(1) as most of the time the queue will only have a few elements. The while
loop removes at most one element per call.
Space Complexity: O(N) in the worst case, as the queue could store up to all the requests if they are all within the 3000ms window.
Code (Python):
from collections import deque
class RecentCounter:
def __init__(self):
self.q = deque()
def ping(self, t: int) -> int:
self.q.append(t)
while self.q[0] < t - 3000:
self.q.popleft()
return len(self.q)
Other languages like Java, C++, Go, JavaScript, TypeScript, and C# use similar queue-based implementations with minor syntactic differences.
This approach utilizes a sorted list (vector/array) to store request times and binary search to find the number of requests within the time window.
Algorithm:
s
is initialized to store request times.ping(t)
:
t
to the list s
.lower_bound
(or bisect_left
in Python) to find the index of the first element in s
that is greater than or equal to t - 3000
. This efficiently identifies the requests outside the window.s
and the index found represents the number of requests within the window.Time Complexity: O(log N) for ping()
on average due to the binary search, where N is the number of calls to ping
. However, the insertion into the sorted array is O(N) in the worst case, thus the overall time complexity becomes O(N).
Space Complexity: O(N), as the list s
can potentially store all request times.
Code (C++):
#include <vector>
#include <algorithm>
class RecentCounter {
public:
vector<int> s;
RecentCounter() {
}
int ping(int t) {
s.push_back(t);
return s.size() - (lower_bound(s.begin(), s.end(), t - 3000) - s.begin());
}
};
Python and Go versions are also provided, adapting the binary search approach to their respective standard libraries. The other languages can also use binary search or similar algorithms to achieve a similar effect, though the queue approach is more efficient in practice for this problem.
Conclusion:
The queue-based approach (Approach 1) is generally preferred due to its better average-case time complexity (O(1) vs O(log N)) and simpler implementation. The binary search approach is presented as an alternative, showcasing a different algorithmic technique. Choose the approach based on your performance needs and coding style preferences. For this problem, the queue is generally the more efficient solution.