Design and implement a Python solution
Company: Anthropic
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Onsite
Quick Answer: This question evaluates Python programming proficiency, algorithm design, data structure selection and justification, modular coding practices, unit testing, and time/space complexity analysis.
Constraints
- 0 <= len(operations) <= 200000
- 1 <= len(key) <= 100
- 0 <= len(value) <= 100
- 1 <= int(timestamp) <= 10^9
- For each individual key, set operation timestamps appear in nondecreasing order in the input.
- If multiple set operations for the same key use the same timestamp, the latest one in operation order should be returned for that timestamp.
Examples
Input: ([['set', 'foo', 'bar', '1'], ['get', 'foo', '1'], ['get', 'foo', '3'], ['set', 'foo', 'bar2', '4'], ['get', 'foo', '4'], ['get', 'foo', '5']],)
Expected Output: ['bar', 'bar', 'bar2', 'bar2']
Explanation: At timestamps 1 and 3, the latest value for 'foo' is 'bar'. After setting 'bar2' at timestamp 4, queries at 4 and 5 return 'bar2'.
Input: ([['get', 'x', '10'], ['set', 'x', 'a', '5'], ['get', 'x', '4'], ['get', 'x', '5']],)
Expected Output: ['', '', 'a']
Explanation: The first query happens before any value is stored for 'x'. The query at timestamp 4 is before the first stored timestamp 5. The query at timestamp 5 returns 'a'.
Input: ([['set', 'love', 'high', '10'], ['set', 'hate', 'bad', '3'], ['set', 'love', 'low', '20'], ['get', 'love', '5'], ['get', 'love', '10'], ['get', 'love', '15'], ['get', 'hate', '100'], ['get', 'love', '20'], ['get', 'love', '25']],)
Expected Output: ['', 'high', 'high', 'bad', 'low', 'low']
Explanation: Different keys maintain independent histories. Queries for 'love' use timestamps 10 and 20, while the query for 'hate' returns its value from timestamp 3.
Input: ([['set', 'k', 'old', '2'], ['set', 'k', 'new', '2'], ['get', 'k', '2'], ['get', 'k', '1']],)
Expected Output: ['new', '']
Explanation: Two values are stored for 'k' at timestamp 2. The later set operation wins for timestamp 2. There is no value at or before timestamp 1.
Input: ([],)
Expected Output: []
Explanation: With no operations, there are no get results to return.
Solution
def solution(operations):
from bisect import bisect_right
# key -> (list of timestamps, list of values)
store = {}
results = []
for op in operations:
if op[0] == 'set':
_, key, value, timestamp_str = op
timestamp = int(timestamp_str)
if key not in store:
store[key] = ([], [])
times, values = store[key]
times.append(timestamp)
values.append(value)
elif op[0] == 'get':
_, key, timestamp_str = op
timestamp = int(timestamp_str)
if key not in store:
results.append('')
continue
times, values = store[key]
idx = bisect_right(times, timestamp) - 1
if idx < 0:
results.append('')
else:
results.append(values[idx])
return resultsTime complexity: O(n log h), where n is the number of operations and h is the maximum number of stored timestamps for any single key. Each set is O(1), and each get uses binary search.. Space complexity: O(s), where s is the number of set operations stored..
Hints
- Store a separate timestamp history for each key instead of scanning all operations for every get.
- Because timestamps for each key are stored in sorted order, binary search can find the latest timestamp not greater than the query time.