Design a key-value store with getLast
Company: SoFi
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Technical Screen
Quick Answer: Design a key-value store with getLast evaluates algorithm design, data structures, correctness, complexity, edge cases, and implementation details in a realistic interview setting. A strong answer states assumptions, handles edge cases, explains trade-offs, and shows how to validate the result clearly.
Constraints
- Keys are strings; values are integers.
- add on an existing key overwrites the value and refreshes its recency (becomes last).
- get returns null/None for a missing key and never changes which entry is last.
- remove is a no-op on a missing key; removing the last entry promotes the next most recent live entry to last.
- getLast on an empty store returns null/None.
- All operations must be O(1) average time.
Examples
Input: [["add", "a", 1], ["add", "b", 2], ["getLast"], ["get", "a"], ["getLast"]]
Expected Output: [["b", 2], 1, ["b", 2]]
Explanation: After adding a then b, last is b. get(a) returns 1 but does not change last, so the second getLast is still b.
Input: [["add", "a", 1], ["add", "b", 2], ["remove", "b"], ["getLast"]]
Expected Output: [["a", 1]]
Explanation: Removing the current last (b) promotes the next most recent live entry, a, to last.
Input: [["getLast"], ["get", "x"]]
Expected Output: [null, null]
Explanation: Empty store: getLast returns null and get of a missing key returns null.
Input: [["add", "k", 10], ["add", "k", 20], ["get", "k"], ["getLast"]]
Expected Output: [20, ["k", 20]]
Explanation: Re-adding an existing key overwrites the value to 20 and refreshes recency; k is last with value 20.
Input: [["add", "a", 1], ["add", "b", 2], ["add", "c", 3], ["remove", "c"], ["remove", "a"], ["getLast"], ["add", "d", 4], ["getLast"], ["remove", "d"], ["getLast"]]
Expected Output: [["b", 2], ["d", 4], ["b", 2]]
Explanation: After removing c then a, the live order is [b]; adding d makes it last; removing d falls back to b.
Input: [["add", "a", 1], ["remove", "a"], ["getLast"]]
Expected Output: [null]
Explanation: Removing the only entry empties the store, so getLast returns null.
Hints
- A hash map alone gives O(1) add/get/remove but cannot answer getLast efficiently after the most-recent entry is removed.
- Pair the hash map with a doubly linked list ordered by insertion recency; the tail is always 'last'. Store node pointers in the map so any key can be detached in O(1).
- On add of an existing key, detach its node first, then re-append at the tail so recency is refreshed. On remove, detach and let the previous node become the new tail automatically.
- get must read the value without touching the linked list, so recency is preserved.