Design a time-based key-value data structure that can store multiple values for the same key at different timestamps and retrieve the key's value at a certain timestamp.
Implement the TimeMap
class:
TimeMap()
Initializes the object of the data structure.void set(String key, String value, int timestamp)
Stores the key key
with the value value
at the given time timestamp
.String get(String key, int timestamp)
Returns a value such that set
was called previously, with timestamp_prev <= timestamp
. If there are multiple such values, it returns the value associated with the largest timestamp_prev
. If there are no values, it returns ""
.Example:
Input
["TimeMap", "set", "get", "get", "set", "get", "get"]
[[], ["foo", "bar", 1], ["foo", 1], ["foo", 3], ["foo", "bar2", 4], ["foo", 4], ["foo", 5]]
What data structures would you use, and how would you implement the set
and get
methods? What is the time complexity for each method? Consider edge cases such as when the key does not exist or when the timestamp is smaller than all timestamps for a given key. How can you optimize the get
method if the timestamps for each key are strictly increasing?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Think of this problem like having a journal where you record values with timestamps. The brute force way to retrieve a value at a specific time is to look at every single entry in your journal.
Here's how the algorithm would work step-by-step:
class TimeMap:
def __init__(self):
self.time_value_journal = []
def set(self, key: str, value: str, timestamp: int) -> None:
self.time_value_journal.append((key, value, timestamp))
def get(self, key: str, timestamp: int) -> str:
# This will store the closest value found so far
closest_value = ""
#Iterate through all the key, value, timestamp sets
for journal_key, journal_value, journal_timestamp in self.time_value_journal:
# Check if the keys match
if journal_key == key:
#We need to find the largest timestamp <= given timestamp
if journal_timestamp <= timestamp:
closest_value = journal_value
return closest_value
The optimal approach uses a smart way to quickly find the right timestamp. Instead of checking every single timestamp, we can use a special technique to narrow down our search to the most relevant ones.
Here's how the algorithm would work step-by-step:
class TimeMap:
def __init__(self):
self.key_value_store = {}
def set(self, key, value, timestamp):
if key not in self.key_value_store:
self.key_value_store[key] = []
self.key_value_store[key].append((timestamp, value))
def get(self, key, timestamp):
if key not in self.key_value_store:
return ""
time_value_pairs = self.key_value_store[key]
# Initialize binary search boundaries
left_pointer, right_pointer = 0, len(time_value_pairs) - 1
result = ""
while left_pointer <= right_pointer:
middle_pointer = (left_pointer + right_pointer) // 2
middle_timestamp, middle_value = time_value_pairs[middle_pointer]
# If the middle timestamp is a match or earlier, update
if middle_timestamp <= timestamp:
# This timestamp is valid, so update the result
result = middle_value
# Search for potentially better (later) timestamps
left_pointer = middle_pointer + 1
else:
# The timestamp is too high, search in the left half
right_pointer = middle_pointer - 1
return result
Case | How to Handle |
---|---|
Null or empty key in set operation | Throw an IllegalArgumentException or return an error code to indicate invalid input. |
Null or empty key in get operation | Return an empty string as specified in the problem description when the key does not exist. |
Negative timestamp in set operation | Throw an IllegalArgumentException since timestamp is generally a non-negative integer representing time. |
Zero timestamp in set operation | Handle timestamp zero as a valid time and store accordingly if the requirements don't explicitly disallow it. |
Timestamp already exists for the same key in set operation | Overwrite the previous value with the new value for the given key and timestamp since the latest entry prevails. |
Timestamp in get operation is smaller than all existing timestamps for the given key | Return an empty string as specified in the problem since no valid value exists. |
Large number of set operations causing memory issues | Consider using techniques like data compression or database persistence to handle large datasets exceeding memory capacity. |
Maximum integer value for timestamp | Ensure the code handles the maximum integer value of timestamp correctly to avoid integer overflow issues during comparisons. |