Skip to content
AI360Xpert
Beta
Difficulty: MediumBinary Search

Time Based Key-Value Store

Problem in Plain English

Design a store that saves values for each key at strictly increasing timestamps and returns the latest value at or before a queried time. Unknown keys and times before any save return the empty string.

Problem Statement

Design a time-based key-value data structure that stores multiple values for the same key at different timestamps and retrieves the value at a queried time.

Implement the TimeMap class: TimeMap() initializes the store, set(key, value, timestamp) saves value for key at timestamp, and get(key, timestamp) returns the value with the largest saved time at or before timestamp, or "" when none exists. All set timestamps are strictly increasing.

Constraints

  • 1≤key.length,value.length≤1001 \leq key.length, value.length \leq 100.
  • key and value consist of lowercase English letters and digits.
  • 1≤timestamp≤1071 \leq timestamp \leq 10^7.
  • All timestamps across set calls are strictly increasing; get queries may arrive in any order.
  • At most 2×1052 \times 10^5 total calls are made to set and get.

Examples

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"]

Saving bar at time 1 answers queries at times 1 and 3; after saving bar2 at time 4, queries at times 4 and 5 answer bar2.

Example 2

Input
["TimeMap", "get", "set", "get"] [[], ["missing", 5], ["a", "x", 2], ["a", 1]]
Output
[null, "", null, ""]

Unknown key missing returns "", and querying a at time 1 before its first save at time 2 also returns "".

Example 3

Input
["TimeMap", "set", "set", "set", "get", "get", "get", "get"] [[], ["a", "old", 2], ["b", "other", 4], ["a", "new", 8], ["a", 6], ["b", 3], ["a", 8], ["a", 10]]
Output
[null, null, null, null, "old", "", "new", "new"]

The two keys have separate histories. Querying a at 6 chooses old at 2, because new at 8 is in the future; b at 3 has no eligible save. An exact query at 8 and a later query at 10 both choose new.

Intuition

A key keeps a history rather than one current value. Group saves by key and append each timestamp-value pair: globally increasing set times make every individual history sorted too. For foo in Example 1, a query at 3 uses bar from time 1, while a query at 5 uses bar2 from time 4. The answer is the last history entry whose timestamp is at most the query, not the nearest timestamp and not necessarily the newest entry.

Approaches

Linear Scan Get

Solution Details

Reveal Linear Scan Get: intuition, complexity, and code

Hints

Hint 1
Strictly increasing set times mean each key list is already sorted, so never sort inside get.
Hint 2
The query asks for the largest saved time at or below the target, which is a rightmost-valid-position search.
Hint 3
Keep a res variable, move left past every valid mid, and return res so gaps between saves resolve to the earlier value.

Edge Cases

  • Querying an unknown key returns "" without touching any list.
  • Querying before the first save for a key, such as time 1 after a first save at time 2, returns "".
  • Querying between two saves or far after the last save returns the earlier or final value respectively.

Common Mistakes and Interview Tips

  • Accepting the nearest timestamp even when it is larger than the query, which violates the at-or-before rule.
  • Sorting the history on every get instead of trusting the strictly increasing set order.
  • Returning the first valid entry from the left rather than continuing right for the largest valid time.
  • Overwriting a key with only its latest value loses historical answers such as foo at time 3 after the save at time 4.
  • Using strict timestamp comparison instead of at-or-before rejects exact matches.
  • Returning as soon as a binary-search midpoint is eligible misses a later eligible version; save the candidate and continue right.
  • Changing set order or inserting out-of-order timestamps breaks the sorted-history assumption; get query times themselves need not increase.
  • In Java, the parallel timestamp and value lists must receive one append each per set so their indices remain aligned.

Key Takeaway

When appends arrive in sorted order, group them by key in a hash map and binary search each group for bound queries.