PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates understanding of time-versioned key-value stores, monotonic timestamp assignment, clock skew handling, concurrent writes, appropriate data structures, and time/space complexity analysis.

  • Medium
  • Uber
  • Coding & Algorithms
  • Software Engineer

Design time-versioned KV without timestamp argument

Company: Uber

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: Medium

Interview Round: Onsite

Design a time-versioned key-value store that does not accept a timestamp argument on writes. Support set(key, value) which stores the value with an internally assigned, monotonically increasing timestamp, getLatest(key) which returns the most recent value, and getAtOrBefore(key, wallTime) which returns the value that was current at or before the given wall-clock time. Describe your data structures, how you ensure monotonicity despite clock issues, and the time/space complexity of operations.

Quick Answer: This question evaluates understanding of time-versioned key-value stores, monotonic timestamp assignment, clock skew handling, concurrent writes, appropriate data structures, and time/space complexity analysis.

Implement a simulator for a time-versioned key-value store. The public write API is set(key, value), which does not accept a timestamp from the caller. For deterministic testing, each set operation in the input trace includes the system clock reading observed internally by the store at that moment; this clock reading may repeat or move backwards and must not be used directly as the version timestamp. Assign each write a strictly increasing hybrid logical timestamp (wall, counter): if this is the first write, or the observed clock time is greater than the previous assigned wall component, assign (clockTime, 0); otherwise assign (previousWall, previousCounter + 1). The timestamp order is lexicographic. Support getLatest(key), returning the most recent value written for key, and getAtOrBefore(key, wallTime), returning the value for key with the greatest assigned timestamp whose wall component is at most wallTime. If no such value exists, return the empty string.

Constraints

  • 0 <= len(operations) <= 200000
  • key and value are non-empty strings; value is never the empty string
  • clockTime and wallTime fit in a signed 64-bit integer
  • The system clock readings on set operations may be equal to or less than earlier readings
  • Only set operations create new versions; get operations do not change the store timestamp

Examples

Input: ([['set', 'a', 'v1', '10'], ['getLatest', 'a'], ['getAtOrBefore', 'a', '10'], ['set', 'a', 'v2', '20'], ['getAtOrBefore', 'a', '15'], ['getAtOrBefore', 'a', '20'], ['getLatest', 'a']],)

Expected Output: ['v1', 'v1', 'v1', 'v2', 'v2']

Explanation: The writes receive timestamps (10, 0) and (20, 0). Queries at wall time 15 still see v1, while wall time 20 sees v2.

Input: ([['set', 'k', 'a', '100'], ['set', 'k', 'b', '100'], ['set', 'k', 'c', '99'], ['getAtOrBefore', 'k', '99'], ['getAtOrBefore', 'k', '100'], ['getAtOrBefore', 'k', '101'], ['getLatest', 'k']],)

Expected Output: ['', 'c', 'c', 'c']

Explanation: The clock repeats and then moves backwards, so assigned timestamps are (100, 0), (100, 1), and (100, 2). Nothing exists at wall time 99, and c is the latest version at wall time 100 or later.

Input: ([['set', 'a', 'x', '5'], ['set', 'b', 'y', '4'], ['getAtOrBefore', 'b', '4'], ['getAtOrBefore', 'b', '5'], ['set', 'a', 'z', '6'], ['getAtOrBefore', 'a', '5'], ['getAtOrBefore', 'a', '6']],)

Expected Output: ['', 'y', 'x', 'z']

Explanation: The second write observes clock time 4, but the previous assigned wall component is 5, so b=y receives timestamp (5, 1). Therefore b is not visible at wall time 4 but is visible at wall time 5.

Input: ([],)

Expected Output: []

Explanation: There are no operations, so there are no get results.

Input: ([['getLatest', 'missing'], ['getAtOrBefore', 'missing', '0'], ['set', 'n', 'old', '-5'], ['getAtOrBefore', 'n', '-6'], ['getAtOrBefore', 'n', '-5'], ['set', 'n', 'newer', '-10'], ['getAtOrBefore', 'n', '-5'], ['getLatest', 'n']],)

Expected Output: ['', '', '', 'old', 'newer', 'newer']

Explanation: Missing keys return ''. The first negative-time write gets (-5, 0). The later write observes -10, so it gets (-5, 1) and becomes the current value at wall time -5.

Solution

def solution(operations):
    from bisect import bisect_right

    histories = {}
    outputs = []

    last_wall = None
    last_counter = 0
    inf_counter = len(operations) + 1

    for op in operations:
        kind = op[0]

        if kind == 'set':
            key = op[1]
            value = op[2]
            clock_time = int(op[3])

            if last_wall is None or clock_time > last_wall:
                wall = clock_time
                counter = 0
            else:
                wall = last_wall
                counter = last_counter + 1

            last_wall = wall
            last_counter = counter

            if key not in histories:
                histories[key] = ([], [])
            stamps, values = histories[key]
            stamps.append((wall, counter))
            values.append(value)

        elif kind == 'getLatest':
            key = op[1]
            if key in histories and histories[key][1]:
                outputs.append(histories[key][1][-1])
            else:
                outputs.append('')

        elif kind == 'getAtOrBefore':
            key = op[1]
            wall_time = int(op[2])

            if key not in histories:
                outputs.append('')
                continue

            stamps, values = histories[key]
            idx = bisect_right(stamps, (wall_time, inf_counter)) - 1
            if idx >= 0:
                outputs.append(values[idx])
            else:
                outputs.append('')

        else:
            raise ValueError('unknown operation type')

    return outputs

Time complexity: Per operation: set is O(1), getLatest is O(1), and getAtOrBefore is O(log m), where m is the number of versions for that key. Over n operations, the worst case is O(n log n).. Space complexity: O(w), where w is the number of set operations stored as historical versions..

Hints

  1. Keep every key's versions in timestamp order. Since global assigned timestamps are increasing as operations are processed, each key's history can be appended to directly.
  2. To handle repeated or backwards clock readings, combine the wall-clock component with a logical counter, then binary search for the upper bound (wallTime, infinity).
Last updated: Jun 21, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Maximize Throughput and Count Trigger Components - Uber (medium)
  • Replace Dashes With Nearest Letters - Uber (medium)
  • Find Earliest Column With One - Uber (easy)
  • Solve Wonderful Strings and Grid Queries - Uber (hard)
  • Count Islands After Land Additions - Uber (medium)