Design a logger that returns top-K messages
GoogleSoftware Engineer · Technical ScreenLast updated
Design an in-memory message logger that records timestamped messages and queries the top-K most frequent messages within any given time range.
Task
Design an in-memory logging system that tracks incoming messages with their arrival timestamps and supports querying the top-k most frequent messages within a specified time range [start_time, end_time] (inclusive).
Implement the TopKLogger class:
TopKLogger(): Initializes the logger object.log_message(timestamp: int, message: str) -> None: Records thatmessageoccurred attimestamp. Calls arrive in non-decreasing order oftimestamp.get_top_k(start_time: int, end_time: int, k: int) -> list[str]: Returns a list of thekmost frequent messages logged with timestamps betweenstart_timeandend_time(inclusive). If two messages have the same frequency, the lexicographically smaller message should appear first. If there are fewer thankunique messages in the range, return all of them ordered by frequency then lexicographically.
Interface
class TopKLogger:
def __init__(self):
pass
def log_message(self, timestamp: int, message: str) -> None:
pass
def get_top_k(self, start_time: int, end_time: int, k: int) -> list[str]:
pass
Examples
Example 1
logger = TopKLogger()
logger.log_message(1, "error")
logger.log_message(2, "info")
logger.log_message(3, "error")
logger.log_message(5, "warn")
logger.log_message(6, "info")
logger.log_message(7, "error")
# Between t=1 and t=5: "error" appears 2 times, "info" 1 time, "warn" 1 time.
# Top 2: "error" (count 2), then "info" beats "warn" lexicographically (both count 1).
logger.get_top_k(1, 5, 2) # Returns ["error", "info"]
# Between t=4 and t=7: "warn" (1), "info" (1), "error" (1)
logger.get_top_k(4, 7, 3) # Returns ["error", "info", "warn"]
Constraints
1 <= timestamp <= 10^9timestampvalues inlog_messageare non-decreasing.start_time <= end_time1 <= k <= 1001 <= len(message) <= 50- At most
10^5calls tolog_message. - At most
500calls toget_top_k.
Edge Cases
- No messages exist within
[start_time, end_time]: return an empty list[]. - Fewer than
kunique messages exist: return all unique messages properly sorted. - Multiple messages with the same count: break ties using lexicographical order.
Hints
Hint 1
Because timestamps arrive in non-decreasing order, binary search (e.g., `bisect`) can efficiently locate the indices or timestamps belonging to a query range.
Hint 2
Consider storing the list of occurrence timestamps for each unique message, allowing you to compute a message's frequency in `[start_time, end_time]` in `O(log M)` time per message.
Hint 3
Once frequencies for candidate messages are determined, use a min-heap of size `k` (or a sorted collection) to extract the top `k` elements in `O(U log k)` time, where `U` is the number of candidate messages.
Follow-up questions
- How would you optimize the system if queries always asked for a sliding window (e.g., the last 5 minutes) rather than arbitrary intervals?
- If memory is constrained and you cannot store every timestamp, how could approximate algorithms like the Count-Min Sketch or Heavy Hitters (Misra-Gries) be adapted?
- How would you scale this design to a distributed environment where multiple logging agents write concurrently?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.