【每日算法】最近的请求次数

249 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

最近的请求次数

写一个 RecentCounter 类来计算特定时间范围内最近的请求。

请你实现 RecentCounter 类:

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

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

示例

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

第一行是调用函数名,第二行是函数的参数:

  1. 调用 RecentCounter,初始化计数器,返回空
  2. 调用 ping,参数是 1,即查询窗口在 [-2999, 1] 之间有多少 ping。当前请求数组:[1] ,返回 1
  3. 调用 ping,参数是 100,即查询窗口在 [-2900, 100] 之间有多少 ping。当前请求数组:[1, 100] ,返回 2
  4. 调用 ping,参数是 3001,即查询窗口在 [1, 3001] 之间有多少 ping。当前请求数组:[1, 100, 3001] ,返回 3
  5. 调用 ping,参数是 3002,即查询窗口在 [2, 3002] 之间有多少 ping。当前请求数组:[1, 100, 3001, 3002] ,返回 3

思路

需要注意的点:

  • 返回过去 3000 毫秒内的请求数 [t-3000, t] ,是一个左闭右闭的区间
  • 每次的 ping 是严格递增的

方法1:队列

我们可以用一个队列来维护发生请求的时间,当在时间 t 收到请求时,将时间 t 入队、

由于每次收到的请求的时间都比之前的大,因此队首到队尾的时间是单调递增的。

 var RecentCounter = function() {
   this.queue = []
 }
 RecentCounter.prototype.ping = function(t) {
   this.queue.push(t)
   while(this.queue[0] < t - 3000) {
     this.queue.shift()
   }
   return this.queue.length
 }

方法2:快慢指针

  • 定义一个数组和快慢指针:arr, slowfast
  • 每次调用 ping 函数(请求时间 t进入数组),都让 fast 指向当前 t
  • 然后对 slow 进行 while 判断,使其前进到小于 t - 3000 的位置
  • 最后返回快慢指针位置的差值即可
 var RecentCounter = function() {
   this.arr = []
   this.fast = 0
   this.slow = 0
 }
 RecentCounter.prototype.ping = function(t) {
   this.arr[this.fast++] = t
   while(this.arr[this.slow] < t - 3000) this.slow++
   // 返回数组的大小 = 发生的请求数
   return this.fast - this.slow
 }

\