Design a time-windowed key-value store
Company: StackAdapt
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: easy
Interview Round: Technical Screen
Quick Answer: This question evaluates a candidate's ability to design efficient data structures and algorithms for a time-windowed key-value store, focusing on expiration handling, update semantics, and maintaining aggregate metrics under memory constraints.
Constraints
- 0 <= windowMs <= 10^12
- 0 <= len(operations) <= 200000
- Operation timestamps are integers and are nondecreasing
- Keys are strings
- Values are numeric integers or floats
- All currently valid keys fit in memory, but the total lifetime of updates may be large
Examples
Input: (10000, [['put', 0, 'a', 10], ['put', 1, 'b', 20], ['avg', 1], ['get', 10000, 'a'], ['avg', 10001], ['get', 10001, 'a']])
Expected Output: [15.0, 10, 20.0, None]
Explanation: At t=1 both a and b are valid, so the average is 15.0. At t=10000, a is exactly on the boundary and is still valid. At t=10001, a is expired but b is still valid.
Input: (5, [['put', 0, 'x', 10], ['put', 2, 'y', 30], ['put', 4, 'x', 20], ['avg', 4], ['get', 6, 'x'], ['get', 6, 'y'], ['avg', 8]])
Expected Output: [25.0, 20, 30, 20.0]
Explanation: Updating x replaces its old value and timestamp. At t=4, x=20 and y=30, average 25.0. At t=8, y's timestamp 2 is outside the window, leaving only x.
Input: (0, [['put', 5, 'a', 1], ['put', 5, 'b', 3], ['avg', 5], ['get', 5, 'a'], ['avg', 6], ['put', 6, 'a', 7], ['get', 6, 'a'], ['avg', 6]])
Expected Output: [2.0, 1, None, 7, 7.0]
Explanation: With a zero-length window, only entries with timestamp exactly equal to now are valid. The entries from t=5 expire at t=6.
Input: (10, [['put', 100, 'a', -5], ['put', 105, 'b', 15], ['avg', 106], ['put', 111, 'c', -10], ['avg', 111], ['get', 111, 'a'], ['avg', 116]])
Expected Output: [5.0, 2.5, None, -10.0]
Explanation: Negative values are included in the running average. At t=111, a has expired, so b and c average to 2.5. At t=116, only c remains valid.
Input: (10, [])
Expected Output: []
Explanation: There are no operations, so there are no query results.
Input: (3, [['put', 0, 'k', 5], ['get', 3, 'k'], ['get', 4, 'k'], ['avg', 4]])
Expected Output: [5, None, None]
Explanation: At t=3, k is exactly on the boundary and valid. At t=4, it is older than now - windowMs and has expired.
Hints
- Use a hash map for direct key lookup, but also keep keys ordered by their latest update timestamp so expired entries can be removed from oldest to newest.
- When Put updates an existing key, make sure the old value is removed from the running sum and the key is moved to the newest position. Get should not move the key.