Easy

题目描述

你有一个 RecentCounter 类来统计特定时间范围内最近的请求次数。

请你实现 RecentCounter 类:

  • RecentCounter() 初始化计数器,请求数为 0 。
  • int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。

保证每次对 ping 的调用都使用比之前调用更大的 t 值。

示例 1:

输入:
["RecentCounter", "ping", "ping", "ping", "ping"]
[[], [1], [100], [3001], [3002]]
输出:
[null, 1, 2, 3, 3]

解释:
RecentCounter recentCounter = new RecentCounter();
recentCounter.ping(1);     // requests = [1], 范围是 [-2999,1],返回 1
recentCounter.ping(100);   // requests = [1, 100], 范围是 [-2900,100],返回 2
recentCounter.ping(3001);  // requests = [1, 100, 3001], 范围是 [1,3001],返回 3
recentCounter.ping(3002);  // requests = [1, 100, 3001, 3002], 范围是 [2,3002],返回 3

提示:

  • 1 <= t <= 10^9
  • 保证每次对 ping 调用所使用的 t 值都 严格递增
  • 至多调用 ping 方法 10^4

解题思路

解题思路

这道题要求我们统计过去 3000 毫秒内的请求次数。由于每次调用 ping 的时间 t 都是严格递增的,我们可以利用这个特性来优化解决方案。

方法分析:

  1. 暴力解法:使用数组存储所有时间戳,每次 ping 时遍历数组统计范围内的请求数。时间复杂度 O(n),空间复杂度 O(n)。

  2. 队列优化(推荐):使用队列存储时间戳,利用时间严格递增的特性。每次 ping 时,先移除队列中超出 3000 毫秒范围的旧请求,然后添加新请求,返回队列长度即可。

队列解法的核心思想:

  • 队列保存所有在有效时间窗口内的请求时间戳
  • 由于时间严格递增,队列中的时间戳天然有序
  • 每次新请求到来时,从队头移除所有过期的请求(时间小于 t-3000 的请求)
  • 将新请求时间加入队尾,返回队列当前大小

这种方法的优势是:

  • 时间复杂度:平均 O(1),最坏 O(n)(当需要清理大量过期请求时)
  • 空间复杂度:O(W),其中 W 是时间窗口内的最大请求数,最多 3001 个

代码实现

class RecentCounter {
private:
    queue<int> requests;
    
public:
    RecentCounter() {
        
    }
    
    int ping(int t) {
        requests.push(t);
        
        while (!requests.empty() && requests.front() < t - 3000) {
            requests.pop();
        }
        
        return requests.size();
    }
};
class RecentCounter:

    def __init__(self):
        self.requests = []

    def ping(self, t: int) -> int:
        self.requests.append(t)
        
        while self.requests and self.requests[0] < t - 3000:
            self.requests.pop(0)
        
        return len(self.requests)
public class RecentCounter {
    private Queue<int> requests;

    public RecentCounter() {
        requests = new Queue<int>();
    }
    
    public int Ping(int t) {
        requests.Enqueue(t);
        
        while (requests.Count > 0 && requests.Peek() < t - 3000) {
            requests.Dequeue();
        }
        
        return requests.Count;
    }
}
var RecentCounter = function() {
    this.requests = [];
};

RecentCounter.prototype.ping = function(t) {
    this.requests.push(t);
    
    while (this.requests.length > 0 && this.requests[0] < t - 3000) {
        this.requests.shift();
    }
    
    return this.requests.length;
};

复杂度分析

复杂度类型复杂度说明
时间复杂度O(1) 均摊每个请求最多被添加和移除一次
空间复杂度O(W)W 为时间窗口内的最大请求数,最多 3001 个