Design Hit Counter
要點:因為是second granularity,所以可以用以秒為單位的circular buffer方法。這題簡單在只需要count過去300秒的,增加難度可以count過去秒,分鐘,小時。
- 2個時間點都有可能更新超時的統計:query和hit
- 一種簡單方法是分開計timestamp和hit:每次timestamp%300的slot里的ts和當前時間比較:因為可以用記錄的ts來區分當前slot是否過期,query可以不更新只統計。同樣,hit只要更新當前slot:+1(有效)or 1(過期)
- 如果不記錄timestamp,需要記錄lastSec(實際就是上次隊頭):而這次curSec更新為新head
- why [lastSec+1, curSec] is cleaned up? 因為curSec是新的circular buffer的隊頭,根據題意,隊列的head和tail是相連的(or tail是head的下一個)。新的head更新前就把上一次隊尾開始的元素清空(也就是超時的部分)
- 擴展:lastMiniute的更新?[lastSec-60+1, curSec-60]:在這兩個時間之間要清除:無論curSec和lastSec差>60 or <60:之前lastSec和curSec之間已經清零(注意更新minute要在seconds清零之后),所以實際減去的只是lastSec-60開始到curSec-60沒清零的部分,保留的是curSec-60+1之后這部分:注意curSec-60+1是過去1分鐘的最后一秒
- 特殊情況:curSec-lastSec>300:不用一個個清零了。curSec==lastSec情況不用特殊考慮,因為是從lastSec+1開始清零
- 本題count更新和擴展中的hour更新一個意思
https://repl.it/C9qu/3
# 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?class HitCounter(object):def __init__(self):"""Initialize your data structure here."""self.lastSec = 0self.seconds = [0]*300self.count = 0def _cleanup(self, timestamp):if timestamp-self.lastSec>300:self.seconds = [0]*300self.count = 0else:for i in xrange(self.lastSec+1, timestamp+1):self.count-=self.seconds[i%300]self.seconds[i%300]=0def hit(self, timestamp):"""Record a hit.@param timestamp - The current timestamp (in seconds granularity).:type timestamp: int:rtype: void"""self._cleanup(timestamp)self.count+=1 self.seconds[timestamp%300]+=1self.lastSec = timestampdef getHits(self, timestamp):"""Return the number of hits in the past 5 minutes.@param timestamp - The current timestamp (in seconds granularity).:type timestamp: int:rtype: int"""self._cleanup(timestamp)self.lastSec = timestampreturn self.count# Your HitCounter object will be instantiated and called as such:
# obj = HitCounter()
# obj.hit(timestamp)
# param_2 = obj.getHits(timestamp)