AlgoMaster Logo

Time Based Key-Value Store

Last Updated: March 29, 2026

medium
4 min read

Understanding the Problem

We need to build a data structure that associates keys with values, but with a twist: each key can have multiple values stored at different points in time. When we retrieve a value, we don't just want the latest one. We want the value that was current at a specific timestamp, meaning the value set at the largest timestamp that doesn't exceed our query timestamp.

Think of it like version control for a key-value store. Each set call creates a new version, and each get call asks "what was the value at this point in time?" If no exact match exists, we want the most recent version before that time.

The critical observation is that timestamps for set calls are strictly increasing. This means the timestamps for each key are already sorted, which opens the door to binary search instead of scanning through every entry.

Key Constraints:

  • 1 <= timestamp <= 10^7 and timestamps are strictly increasing -- The sorted order of timestamps is guaranteed. We never need to sort anything ourselves.
  • At most 2 * 10^5 calls to set and get -- With up to 200,000 operations, a linear scan per get call could mean up to 200,000 200,000 = 4 10^10 operations in the worst case. We need something better for get.
  • key.length, value.length <= 100 -- String operations are cheap. The bottleneck is the lookup strategy, not string handling.

Approach 1: Hash Map with Linear Scan

Intuition

The most straightforward design stores each key's history as a list of (timestamp, value) pairs inside a hash map. For set, we just append to the list. For get, we scan backward through the list to find the largest timestamp that doesn't exceed the query timestamp.

Since timestamps come in strictly increasing order, the list is naturally sorted. Scanning backward means we hit the most recent valid entry first, so we can return as soon as we find a timestamp less than or equal to our target.

Algorithm

  1. Initialize a hash map where each key maps to a list of (timestamp, value) pairs.
  2. For set(key, value, timestamp): append (timestamp, value) to the list for key.
  3. For get(key, timestamp): look up the list for key. Iterate backward through the list. Return the value of the first entry whose timestamp is less than or equal to timestamp. If no such entry exists, return "".

Example Walkthrough

1Initial: store is empty
1/6

Code

The linear scan works but doesn't leverage the sorted order of timestamps. Since timestamps are strictly increasing, can we use binary search to find the right entry in O(log n) instead of O(n)?

Approach 2: Hash Map with Binary Search (Optimal)

Intuition

Since timestamps arrive in strictly increasing order, the list of timestamps for each key is already sorted. This is exactly the setup where binary search shines. Instead of scanning backward through potentially thousands of entries, we can jump straight to the right answer in O(log n) time.

The specific binary search variant we need is "find the largest value less than or equal to the target." This is sometimes called finding the "floor" value. We want the rightmost timestamp that doesn't exceed our query timestamp.

Here's how the binary search works: we maintain a search range [left, right]. We check the middle element. If timestamps[mid] <= target, this could be our answer, but there might be a better (larger) one to the right, so we move left = mid + 1 and record mid as a candidate. If timestamps[mid] > target, the middle timestamp is too new, so we move right = mid - 1. When the search ends, our last recorded candidate is the answer.

Algorithm

  1. Initialize a hash map where each key maps to a list of (timestamp, value) pairs.
  2. For set(key, value, timestamp): append (timestamp, value) to the list for key.
  3. For get(key, timestamp):
    • Look up the list for key. If the key doesn't exist, return "".
    • Binary search the timestamps for the largest one less than or equal to timestamp.
    • Set left = 0, right = list.size() - 1, result = -1.
    • While left <= right: compute mid = (left + right) / 2. If timestamps[mid] <= timestamp, set result = mid and move left = mid + 1. Otherwise, move right = mid - 1.
    • If result != -1, return the value at index result. Otherwise, return "".

Example Walkthrough

1Initial: no timestamps stored for key "foo"
1/7

Code