[路飞]_leetcode刷题_933. 最近的请求次数

132 阅读2分钟

「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

题目

最近的请求次数

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

请你实现 RecentCounter 类:

RecentCounter() 初始化计数器,请求数为 0 。 int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。 保证 每次对 ping 的调用都使用比之前更大的 t 值。

思路:

头脑风暴的第一反应,是申明一个数组用来存储所有请求,然后每次ping的时候,往数组里push请求的时间t,并且遍历整个数组,看大于t的请求有多少个。虽然这个解法不怎么优雅,但也算能解决问题。

代码如下:

var RecentCounter = function() {
    this.items = [];
};

/** 
 * @param {number} t
 * @return {number}
 */
RecentCounter.prototype.ping = function(t) {
    this.items.push(t);
    let time = t-3000;
    let count = 0;
    for(let i=0;i<this.items.length;i++){
        if(this.items[i]>=time){
            count++;
        }
    }
    return count;
};

队列解法

有了暴力解法的基础,我们其实可以转换一下思想,首先我们其实没有必要维护所有的请求,因为我们需要的只是[t-3000,t]范围内的请求,然后我们遍历的判断可以由大于time则计数变为小于time则去除,这样剩下来的就都是满足[t-3000,t]这个条件的。

其实这就是一个队列的思想,我们维护一个队列,这个队列里存储着[t-3000,t]的请求,每推进来一个请求数据,我们就去判断队列的头元素是否在队列条件内,不在就踢出队列,那么我们最终返回队列的长度即是所有在[t-3000,t]内的元素。

代码如下:

var RecentCounter = function() {
    this.items = []
};

/** 
 * @param {number} t
 * @return {number}
 */
RecentCounter.prototype.ping = function(t) {
    this.items.push(t);
    let time = t-3000;
    while(this.items[0] < time){
        this.items.shift();
    }
    return this.items.length;
};

但这个写法其实有点问题,就是每次shift数组的时候,后面的元素都会向前移动,多次执行shift操作,则会移动多次。我们其实可以优化一下,引入headIndex来标记队列头元素,每次判断headIndex是否满足[i-3000,i],不满足则+1,最后返回数组length-headindex的值即为队列长度。

代码如下:

var RecentCounter = function() {
    this.items = [];
    this.headIndex = 0;
};

/** 
 * @param {number} t
 * @return {number}
 */
RecentCounter.prototype.ping = function(t) {
    this.items.push(t);
    let time = t-3000;
    while(this.items[this.headIndex] < time){
        this.headIndex ++;
    }
    return this.items.length - this.headIndex;
};