As asked
Implement a least-recently-used cache that supports get(key) and put(key, value) both in O(1) time. When the cache is full and a new key is inserted, evict the least recently used entry. Do not use any built-in ordered dictionary types.
Sample answer outline
The classic solution combines a hashmap for O(1) lookup with a doubly linked list to track recency order. On get, move the node to the front. On put, add to front; if over capacity, remove from the tail and delete from the map. A strong answer walks through the dummy head and tail sentinel trick to avoid null checks, then discusses thread-safety if the cache is shared across goroutines or threads.
Reference implementation (python)
class Node:
def __init__(self, k=0, v=0):
self.key, self.val = k, v
self.prev = self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.cap = capacity
self.cache = {}
self.head, self.tail = Node(), Node()
self.head.next = self.tail
self.tail.prev = self.head
def _remove(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def _insert(self, node):
node.next = self.head.next
node.prev = self.head
self.head.next.prev = node
self.head.next = node
def get(self, key: int) -> int:
if key in self.cache:
self._remove(self.cache[key])
self._insert(self.cache[key])
return self.cache[key].val
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
self._remove(self.cache[key])
self.cache[key] = Node(key, value)
self._insert(self.cache[key])
if len(self.cache) > self.cap:
lru = self.tail.prev
self._remove(lru)
del self.cache[lru.key]Expect these follow-ups
- How would you make this thread-safe for concurrent reads and writes?
- Can you extend this to support a TTL on each entry without changing the time complexity of get and put?