Time Based Key-Value Store medium
Problem Statement
Design a time-based key-value data structure that can store multiple values for the same key at different time stamps. Implement the TimeMap
class:
TimeMap()
: Initializes the object.set(key: str, value: str, timestamp: int)
: Stores the keykey
with the valuevalue
at the given time timestamp.get(key: str, timestamp: int)
: Returns a value such that it was stored at a time less than or equal totimestamp
. If there are multiple such values, it returns the one associated with the largest timestamp less than or equal to timestamp. If there is no value, it returns "".
Example 1
Input
["TimeMap", "set", "get", "get", "set", "get", "get"]
[[], ["foo", "bar", 1], ["foo", 1], ["foo", 3], ["foo", "bar2", 4], ["foo", 4], ["foo", 5]]
Output
[null, null, "bar", "bar", null, "bar2", "bar2"]
Explanation
TimeMap timeMap = new TimeMap();
timeMap.set("foo", "bar", 1); // store the key "foo" and value "bar" along with timestamp = 1.
timeMap.get("foo", 1); // return "bar"
timeMap.get("foo", 3); // return "bar", since there is no value corresponding to foo at timestamp 3 and timestamp 2, then the only value is at timestamp 1 ie "bar"
timeMap.set("foo", "bar2", 4); // store the key "foo" and value "bar2" along with timestamp = 4.
timeMap.get("foo", 4); // return "bar2"
timeMap.get("foo", 5); // return "bar2"
Example 2
Input
["TimeMap", "set", "set", "get", "get", "get"]
[[], ["love", "high", 10], ["love", "low", 20], ["love", 5], ["love", 10], ["love", 15]]
Output
[null, null, null, "", "high", "high"]
Explanation
TimeMap timeMap = new TimeMap();
timeMap.set("love", "high", 10);
timeMap.set("love", "low", 20);
timeMap.get("love", 5); // return "" because there is no value with timestamp <= 5
timeMap.get("love", 10); // return "high"
timeMap.get("love", 15); // return "high"
Steps
-
Data Structure: Use a dictionary to store the key-value pairs. The value for each key will be a list of (timestamp, value) tuples, sorted by timestamp. This allows efficient retrieval of values based on timestamp.
-
set(key, value, timestamp)
: Append the(timestamp, value)
tuple to the list associated with the given key. -
get(key, timestamp)
:- If the key doesn't exist, return "".
- Perform a binary search on the list of (timestamp, value) tuples for the key.
- Find the largest timestamp less than or equal to the given timestamp.
- Return the corresponding value.
Explanation
The key to efficiency in this problem is using a sorted list of timestamps for each key. This allows us to use binary search in the get
method, resulting in logarithmic time complexity. A simple linear scan would lead to a much slower solution. The binary search efficiently finds the latest value within the specified timestamp constraint.
Code
class TimeMap:
def __init__(self):
self.data = {}
def set(self, key: str, value: str, timestamp: int) -> None:
if key not in self.data:
self.data[key] = []
self.data[key].append((timestamp, value))
def get(self, key: str, timestamp: int) -> str:
if key not in self.data:
return ""
values = self.data[key]
l, r = 0, len(values) - 1
res = ""
while l <= r:
mid = (l + r) // 2
if values[mid][0] <= timestamp:
res = values[mid][1]
l = mid + 1
else:
r = mid - 1
return res
Complexity
-
Time Complexity:
set
: O(1) on average (amortized), O(n) in the worst case if many elements need to be shifted for insertion. In practice, O(1) is a reasonable approximation given many inserts.get
: O(log n), where n is the number of (timestamp, value) pairs associated with the key. This is due to the binary search.
-
Space Complexity: O(N), where N is the total number of (key, value, timestamp) entries stored.