Design cache with least-recently-used eviction
Company: Microsoft
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
You are asked to design an in-memory key–value cache that supports a **least-recently-used (LRU) eviction policy**.
The cache must support the following operations:
- `get(key) -> value`:
- If `key` exists in the cache, return its associated `value` and mark this entry as **most recently used**.
- If `key` does not exist, return `-1` (or an equivalent sentinel value indicating a miss).
- `put(key, value) -> void`:
- Insert or update the value associated with `key`.
- If the `key` already exists, update its value and mark it as **most recently used**.
- If inserting the new key would cause the number of items in the cache to exceed a fixed **capacity** (given when the cache is created), you must **evict the least recently used** entry first.
**Requirements:**
- The cache is initialized with an integer `capacity > 0`.
- Both `get` and `put` operations must run in **amortized O(1) time**.
- Clearly describe the data structures you will use to achieve O(1) time for both operations.
**Example behavior (for illustration only):**
```text
Initialize cache with capacity = 2
put(1, 1) # cache = {1=1}
put(2, 2) # cache = {1=1, 2=2} (2 is most recently used)
get(1) -> 1 # returns 1, cache order: 2 (LRU), 1 (MRU)
put(3, 3) # capacity exceeded, evict 2 (LRU), cache = {1=1, 3=3}
get(2) -> -1 # 2 was evicted
put(4, 4) # capacity exceeded, evict 1 (LRU), cache = {3=3, 4=4}
get(1) -> -1 # 1 was evicted
get(3) -> 3 # returns 3
get(4) -> 4 # returns 4
```
Quick Answer: This question evaluates understanding of in-memory key–value cache design, eviction policies, and appropriate data-structure choices to achieve amortized O(1) get and put operations.
Simulate an LRU cache and return the outputs of get operations.
Constraints
- Inputs are Python literals matching the function signature.
- Return a deterministic exact-match value.
Examples
Input: (2, [["put",1,1],["put",2,2],["get",1],["put",3,3],["get",2],["put",4,4],["get",1],["get",3],["get",4]])
Expected Output: [1, -1, -1, 3, 4]
Explanation: Standard LRU example.
Input: (1, [["put","a",10],["put","b",20],["get","a"],["get","b"]])
Expected Output: [-1, 20]
Explanation: Capacity one evicts the previous key.
Input: (2, [["put",1,1],["put",1,9],["get",1]])
Expected Output: [9]
Explanation: Updating an existing key refreshes it.
Hints
- Use an ordered map.
- Move keys to the most-recent position after get or put.