1348. Tweet Counts Per Frequency
Read the full problem statement on LeetCode.
Difficulty: medium Acceptance: 45% Topics: Hash Table, Binary Search, Design, Sorting, Ordered Set
View full problem on LeetCode Reading material
Reference solution (spoiler · python)
# Time: add: O(logn),
# query: O(c), c is the total count of matching records
# Space: O(n)
import collections
import random
# Template:
# https://github.com/kamyu104/LeetCode-Solutions/blob/master/Python/design-skiplist.py
class SkipNode(object):
def __init__(self, level=0, val=None):
self.val = val
self.nexts = [None]*level
self.prevs = [None]*level
class SkipList(object):
P_NUMERATOR, P_DENOMINATOR = 1, 2 # P = 1/4 in redis implementation
MAX_LEVEL = 32 # enough for 2^32 elements
def __init__(self, end=float("inf"), can_duplicated=False):
random.seed(0)
self.__head = SkipNode()
self.__len = 0
self.__can_duplicated = can_duplicated
self.add(end)
def lower_bound(self, target):
return self.__lower_bound(target, self.__find_prev_nodes(target))
def find(self, target):
return self.__find(target, self.__find_prev_nodes(target))
def add(self, val):
if not self.__can_duplicated and self.find(val):
return False
node = SkipNode(self.__random_level(), val)
if len(self.__head.nexts) < len(node.nexts):
self.__head.nexts.extend([None]*(len(node.nexts)-len(self.__head.nexts)))
prevs = self.__find_prev_nodes(val)
for i in xrange(len(node.nexts)):
node.nexts[i] = prevs[i].nexts[i]
if prevs[i].nexts[i]:
prevs[i].nexts[i].prevs[i] = node
prevs[i].nexts[i] = node
node.prevs[i] = prevs[i]
self.__len += 1
return True
def remove(self, val):
prevs = self.__find_prev_nodes(val)
curr = self.__find(val, prevs)
if not curr:
return False
self.__len -= 1
for i in reversed(xrange(len(curr.nexts))):
prevs[i].nexts[i] = curr.nexts[i]
if curr.nexts[i]:
curr.nexts[i].prevs[i] = prevs[i]
if not self.__head.nexts[i]:
self.__head.nexts.pop()
return True
def __lower_bound(self, val, prevs):
if prevs:
candidate = prevs[0].nexts[0]
if candidate:
return candidate
return None
def __find(self, val, prevs):
candidate = self.__lower_bound(val, prevs)
if candidate and candidate.val == val:
return candidate
return None
def __find_prev_nodes(self, val):
prevs = [None]*len(self.__head.nexts)
curr = self.__head
for i in reversed(xrange(len(self.__head.nexts))):
while curr.nexts[i] and curr.nexts[i].val < val:
curr = curr.nexts[i]
prevs[i] = curr
return prevs
def __random_level(self):
level = 1
while random.randint(1, SkipList.P_DENOMINATOR) <= SkipList.P_NUMERATOR and \
level < SkipList.MAX_LEVEL:
level += 1
return level
def __len__(self):
return self.__len-1 # excluding end node
def __str__(self):
result = []
for i in reversed(xrange(len(self.__head.nexts))):
result.append([])
curr = self.__head.nexts[i]
while curr:
result[-1].append(str(curr.val))
curr = curr.nexts[i]
return "\n".join(map(lambda x: "->".join(x), result))
class TweetCounts(object):
def __init__(self):
self.__records = collections.defaultdict(lambda: SkipList(can_duplicated=True))
self.__lookup = {"minute":60, "hour":3600, "day":86400}
def recordTweet(self, tweetName, time):
"""
:type tweetName: str
:type time: int
:rtype: None
"""
self.__records[tweetName].add(time)
def getTweetCountsPerFrequency(self, freq, tweetName, startTime, endTime):
"""
:type freq: str
:type tweetName: str
:type startTime: int
:type endTime: int
:rtype: List[int]
"""
delta = self.__lookup[freq]
result = [0]*((endTime-startTime)//delta+1)
it = self.__records[tweetName].lower_bound(startTime)
while it is not None and it.val <= endTime:
result[(it.val-startTime)//delta] += 1
it = it.nexts[0]
return result
# Time: add: O(n),
# query: O(rlogn), r is the size of result
# Space: O(n)
import bisect
class TweetCounts2(object):
def __init__(self):
self.__records = collections.defaultdict(list)
self.__lookup = {"minute":60, "hour":3600, "day":86400}
def recordTweet(self, tweetName, time):
"""
:type tweetName: str
:type time: int
:rtype: None
"""
bisect.insort(self.__records[tweetName], time)
def getTweetCountsPerFrequency(self, freq, tweetName, startTime, endTime):
"""
:type freq: str
:type tweetName: str
:type startTime: int
:type endTime: int
:rtype: List[int]
"""
delta = self.__lookup[freq]
i = startTime
result = []
while i <= endTime:
j = min(i+delta, endTime+1)
result.append(bisect.bisect_left(self.__records[tweetName], j) - \
bisect.bisect_left(self.__records[tweetName], i))
i += delta
return result
# Time: add: O(1),
# query: O(n)
# Space: O(n)
class TweetCounts3(object):
def __init__(self):
self.__records = collections.defaultdict(list)
self.__lookup = {"minute":60, "hour":3600, "day":86400}
def recordTweet(self, tweetName, time):
"""
:type tweetName: str
:type time: int
:rtype: None
"""
self.__records[tweetName].append(time)
def getTweetCountsPerFrequency(self, freq, tweetName, startTime, endTime):
"""
:type freq: str
:type tweetName: str
:type startTime: int
:type endTime: int
:rtype: List[int]
"""
delta = self.__lookup[freq]
result = [0]*((endTime- startTime)//delta+1)
for t in self.__records[tweetName]:
if startTime <= t <= endTime:
result[(t-startTime)//delta] += 1
return result
Solution from kamyu104/LeetCode-Solutions · MIT
Similar questions