[LeetCode] 362. Design Hit Counter

Design a hit counter which counts the number of hits received in the past 5 minutes.

Each function accepts a timestamp parameter (in seconds granularity) and you may assume that calls are being made to the system in chronological order (ie, the timestamp is monotonically increasing). You may assume that the earliest timestamp starts at 1.

It is possible that several hits arrive roughly at the same time.

Example:
HitCounter counter = new HitCounter();

// hit at timestamp 1.
counter.hit(1);

// hit at timestamp 2.
counter.hit(2);

// hit at timestamp 3.
counter.hit(3);

// get hits at timestamp 4, should return 3.
counter.getHits(4);

// hit at timestamp 300.
counter.hit(300);

// get hits at timestamp 300, should return 4.
counter.getHits(300);

// get hits at timestamp 301, should return 3.
counter.getHits(301);
Follow up:
What if the number of hits per second could be very large? Does your design scale?

敲击计数器。

设计一个敲击计数器,使它可以统计在过去5分钟内被敲击次数。每个函数会接收一个时间戳参数(以秒为单位),你可以假设最早的时间戳从1开始,且都是按照时间顺序对系统进行调用(即时间戳是单调递增)。在同一时刻有可能会有多次敲击。

思路

两种思路。

  1. 用一个 queue 记录每次敲击的 timestamp,当试图访问 getHits 函数的时候,查看 queue 头部的元素的 timestamp 和当前 timestamp 是否差值大于 300,若大于则说明无效了,需要弹出 queue 中所有跟目前 timestamp 差值大于 300 的元素,queue 的 size 则是过去五分钟内的敲击次数。

这个做法在遇到一些极端的 case 的时候会有问题,比如 time = 1 的时候我敲击了一次,但是 time = 5 的时候我敲击了一万次,time = 6 的时候我又敲击了两万次。这样重复多次,如果在 300 秒以内有太多上万次的敲击,queue 可能会存不下。所以参见方法二的优化。

  1. 用两个数组 times 和 hits,分别记录敲击的时间和次数。敲击的时候,先用 timestamp % 300,这样我们就可以直接跳过 timestamp - 300 甚至更早于这个时间点的敲击了。如果 timestamp 做模运算的那个位置上有值但是不等于当前的 timestamp,说明这个位置上的 timestamp 是 五分钟以前甚至更早的,此时我们可以直接把这个位置的数字重置为 1。若小于300秒则直接在hits同样位置++,说明这依然是五分钟以内的敲击,同时在times数组内记录最新的timestamp。统计敲击次数的时候,是遍历hits数组,若hits[i]不为0,则判断当前i位置上times和timestamp的差值是否又大于300,若大于则不能加入结果集。

复杂度

时间O(n)
空间O(300) - O(1)

代码

Java实现

class HitCounter {
	private int[] hits;
	private int[] times;

	/** Initialize your data structure here. */
	public HitCounter() {
		hits = new int[300];
		times = new int[300];
	}

	/** Record a hit.
	    @param timestamp - The current timestamp (in seconds granularity). */
	public void hit(int timestamp) {
		int index = timestamp % 300;
		if (times[index] != timestamp) {
			times[index] = timestamp;
			hits[index] = 1;
		} else {
			hits[index]++;
		}
	}

	/** Return the number of hits in the past 5 minutes.
	    @param timestamp - The current timestamp (in seconds granularity). */
	public int getHits(int timestamp) {
		int total = 0;
		for (int i = 0; i < 300; i++) {
			if (timestamp - times[i] < 300) {
				total += hits[i];
			}
		}
		return total;
	}
}

/**
 * Your HitCounter object will be instantiated and called as such:
 * HitCounter obj = new HitCounter();
 * obj.hit(timestamp);
 * int param_2 = obj.getHits(timestamp);
 */

相关题目

362. Design Hit Counter
933. Number of Recent Calls
posted @ 2020-04-14 04:11  CNoodle  阅读(308)  评论(0编辑  收藏  举报