A hash map plus a doubly linked list gives O(1) get and put with least-recently-used eviction. No OrderedDict.
A cache has finite memory, so when it is full something has to go. LRU (least recently used) evicts the entry that has gone longest without being read or written (Week 0, Part 6, section 11.2): with capacity 4 and accesses A, B, C, D, A, B, inserting E evicts C. It is the policy behind most in-process caches and Memcached, and a classic "implement this" interview round.
Implement LRUCache(capacity):
| Method | Does |
|---|---|
get(key) |
the value, or None when missing. A hit makes key the most recently used |
put(key, value) |
inserts or updates key and makes it most recently used. If that pushes the size over capacity, evict the least recently used key |
delete(key) |
removes key; returns True if it was there, False otherwise |
__len__() |
number of entries |
order() |
keys from least to most recently used (the tests use it to check recency) |
Rules the tests check:
get and put run in O(1): the hidden tests count key comparisons, and scanning a list on every access fails them.capacity below 1 raises ValueError.collections.OrderedDict and functools.lru_cache are off limits, as they usually are in the interview.In JavaScript and TypeScript the methods are get(key) (null on a miss), put(key, value), delete(key), a size getter in place of __len__, and order() (an array). A capacity below 1 throws a RangeError. A Map remembers insertion order, so "delete the key, set it again, evict map.keys().next().value" is JavaScript's OrderedDict, and it's off limits too: the rule test looks for .keys().next(), .values().next() and .entries().next(). Use the Map only to find a key's node. JavaScript can't count key comparisons, so the O(1) test counts the array elements that indexOf, splice, shift and the like walk over instead.
Write your code, then run 3 example tests and 9 hidden tests. Each run is limited to 8 seconds: an infinite loop gets stopped and the runtime restarts, your code stays.