Hit Counter
出处
Given a server that has requests coming in. Design a data structure such that you can fetch the count of the number requests in the last second, minute and hour.
Solution
对于这个问题,比较容易想到的是对于每个request,我们都分配一个当时的时间戳(timestamp),并且将request根据时间戳排序,则时间戳构成一个完全有序的序列。这样,当我们要搜索一分钟前的request时,可以用二分查找快速定位。其次,如果我们找到了对应的request,如何最快速地知道从这个request至现在一共发生了多少次其他请求?我们可以采用计数的方式,对于每个request,分配一个计数,用以表示这是第几个request。我们只需要用当前计数减去某个request的计数,就可以知道从那个request至现在一共发生了多少次其他请求。
Complexity
我们应用二分查找寻找某个特定时间的request,算法涉及的时间复杂度为O(logn)。
Code
注意,我们简化了overflow的处理,采用long int并且默认整形数据不会越界。读者可以进一步考虑如何处理越界。
#include <time.h>
#include <sys/time.h>
long now() {
struct timeval time;
gettimeofday(&time, NULL);
return (time.tv_sec * 1000000 + time.tv_usec);
}
class HitCounter {
private:
deque<pair<long, int>> hits;
long last_count = 0;
const int second = 1000000;
const int minute = 60 * second;
const int hour = 60 * minute;
void prune() {
auto old = upper_bound(hits.begin(), hits.end(), make_pair(now() - 1 * hour, -1));
if (old != hits.end()) {
hits.erase(hits.begin(), old);
}
}
public:
void hit() {
hits.push_back(make_pair(now(), ++last_count));
prune();
}
long hitsInLastSecond() {
auto before = lower_bound(hits.begin(), hits.end(), make_pair(now() - 1 * second, -1));
if (before == hits.end()) { return 0; }
return last_count - before->second + 1;
}
long hitsInLastMinute() {
auto before = lower_bound(hits.begin(), hits.end(), make_pair(now() - 1 * minute, -1));
if (before == hits.end()) { return 0; }
return last_count - before->second + 1;
}
long hitsInLastHour() {
auto before = lower_bound(hits.begin(), hits.end(), make_pair(now() - 1 * hour, -1));
if (before == hits.end()) { return 0; }
return last_count - before->second + 1;
}
};