敲击计数器。设计一个敲击计数器,使它可以统计在过去5分钟内被敲击次数。每个函数会接收一个时间戳参数(以秒为单位),你可以假设最早的时间戳从1开始,且都是按照时间顺序对系统进行调用(即时间戳是单调递增)。在同一时刻有可能会有多次敲击。例子,
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);
两种思路。
1. 用一个queue记录每次敲击的timestamp,当试图访问getHits函数的时候,查看queue头部的元素的timestamp和当前timestamp是否差值大于300,若大于则说明无效了,需要弹出queue中所有跟目前timestamp差值大于300的元素,queue的size则是过去五分钟内的敲击次数。
2. 用两个数组times和hits,分别记录敲击的时间和次数。敲击的时候,判断timestamp是否在300秒开外了(通过%300的方式),若大于300秒则需要讲hits同样位置的数字重置为1;若小于300秒则直接在hits同样位置++,说明这依然是五分钟以内的敲击,同时在times数组内记录最新的timestamp。统计敲击次数的时候,是遍历hits数组,若hits[i]不为0,则判断当前i位置上times和timestamp的差值是否又大于300,若大于则不能加入结果集。
Java实现
1 class HitCounter { 2 private int[] times; 3 private int[] hits; 4 5 /** Initialize your data structure here. */ 6 public HitCounter() { 7 times = new int[300]; 8 hits = new int[300]; 9 } 10 11 /** Record a hit. 12 @param timestamp - The current timestamp (in seconds granularity). */ 13 public void hit(int timestamp) { 14 int index = timestamp % 300; 15 if (times[index] != timestamp) { 16 times[index] = timestamp; 17 hits[index] = 1; 18 } else { 19 hits[index]++; 20 } 21 } 22 23 /** Return the number of hits in the past 5 minutes. 24 @param timestamp - The current timestamp (in seconds granularity). */ 25 public int getHits(int timestamp) { 26 int total = 0; 27 for (int i = 0; i < 300; i++) { 28 if (timestamp - times[i] < 300) { 29 total += hits[i]; 30 } 31 } 32 return total; 33 } 34 } 35 36 /** 37 * Your HitCounter object will be instantiated and called as such: 38 * HitCounter obj = new HitCounter(); 39 * obj.hit(timestamp); 40 * int param_2 = obj.getHits(timestamp); 41 */