QUESTION
easy
题目描述
写一个 RecentCounter
类来计算最近的请求。
它只有一个方法:ping(int t)
,其中 t
代表以毫秒为单位的某个时间。
返回从 3000
毫秒前到现在的 ping
数。
任何处于 [t - 3000, t]
时间范围之内的 ping
都将会被计算在内,包括当前(指 t
时刻)的 ping
。
保证每次对 ping
的调用都使用比之前更大的 t
值
示例:
输入:inputs = ["RecentCounter","ping","ping","ping","ping"], inputs = [[],[1],[100],[3001],[3002]]
输出:[null,1,2,3,3]
说明
- 每个测试用例最多调用
10000
次ping
- 每个测试用例会使用严格递增的
t
值来调用ping
- 每次调用
ping
都有1 <= t <= 10^9
SOLUTION
此题的关键是读懂题目,如果理解了题目就很好写了。
简单解释一下,大概意思就是你每次 ping
都会伴随一个时间点 t
,而你的任务就是,ping
的同时你要返回 [t - 3000, t]
这个时间段 ping
的次数,注意是闭区间。
方法一(二分搜索)
这个问题的关键就在于给定的 ping 的时间 t
是严格递增的(很真实),而它需要你返回一个区间内的总 ping 数,那么只要我们使用数组来储存每个 ping 的时间点,然后找到第一个不小于 t -3000
的数组下标 index
,通过 size() - index
就能求出我们想要的答案。为了缩短查找时间我们采用二分搜索。
class RecentCounter {
public:
RecentCounter() {}
int ping(int t) {
time.push_back(t);
int l = binary_search_lower_bound(t - 3000);
return time.size() - l;
}
private:
vector<int> time;
int binary_search_lower_bound(int target){
int r = time.size() - 1;
int l = 0;
while(l <= r){
int mid = l + (r - l) / 2;
if(time[mid] < target) l = mid + 1;
else r = mid - 1;
}
return r + 1;
}
};
方法二(二分搜索改进)
仔细思考题目可以发现,由于范围是固定的 3000
,所以如果我们改为每次去查找最后一个小于 t - 3000
数组下标 index
,同时用一个变量保存以用于下一次的二分搜索的左起始点,就能缩短一些查找时间。
class RecentCounter {
public:
RecentCounter() {
index = 0;
}
int ping(int t) {
time.push_back(t);
int res = binary_search(t - 3000);
return time.size() - res - 1;
}
private:
vector<int> time;
int index;
int binary_search(int target){
int r = time.size() - 1;
int l = index;
while(l <= r){
int mid = l + (r - l) / 2;
if(time[mid] < target) l = mid + 1;
else r = mid - 1;
}
return r; //注意这里不是 r + 1
}
};
方法三(队列)
既然 t
严格递增,而查找的范围又是固定的 3000
, 那我每次记录的同时,都把用不着的删掉不就行了吗,用一个队列实现
class RecentCounter {
public:
RecentCounter() {}
int ping(int t) {
time.push(t);
while(time.front() < t - 3000){
time.pop();
}
return time.size();
}
private:
queue<int> time;
};