As asked
You are implementing a server-side in-memory cache for a Node.js API that stores expensive database query results. It must evict the least recently used entry when capacity is reached. Implement an LRU cache class with get(key) and put(key, value) in O(1) time. Explain your data structure choices in terms of memory layout and how they behave under high-concurrency API traffic.
Sample answer outline
Use a doubly linked list to track access order (most recent at head, LRU at tail) and a hash map from key to list node for O(1) lookup. put moves the node to the head; get also moves the node to the head. When capacity is exceeded, remove the tail node and its hash map entry. A strong answer mentions that JavaScript's Map preserves insertion order and can be used for a simpler implementation, and handles the edge case where put is called with an existing key (update value, promote to head).
Reference implementation (javascript)
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.map = new Map();
}
get(key) {
if (!this.map.has(key)) return -1;
const value = this.map.get(key);
this.map.delete(key);
this.map.set(key, value);
return value;
}
put(key, value) {
if (this.map.has(key)) this.map.delete(key);
this.map.set(key, value);
if (this.map.size > this.capacity) {
this.map.delete(this.map.keys().next().value);
}
}
}Expect these follow-ups
- How would you make this thread-safe in a Go or Java implementation?
- How would you modify this to support a TTL per key in addition to LRU eviction?