Intuition
An LRU cache needs two things: O(1) lookup by key, and O(1) reordering so the most recently used key sits at one end and the oldest sits at the other. Python's OrderedDict gives us both for free — move_to_end repositions a key in O(1), and popitem(last=False) evicts the oldest entry in O(1).
Explanation
Why OrderedDict
OrderedDict is a hash map that also keeps insertion order. Crucially, it exposes:
move_to_end(key, last=True)— bumpskeyto the most recently used end in O(1).popitem(last=False)— removes and returns the oldest entry in O(1).
Combine those with normal dict get/set and you have everything LRU needs.
Steps
For each operation:
get(key):- If
keynot in the dict, return-1. - Otherwise
move_to_end(key)(refreshes its recency) and return its value.
- If
put(key, value):- If
keyalready exists, move it to end (so the update counts as recent). - Set
self.od[key] = value(this also moves a brand-new key to the end automatically). - If size now exceeds
capacity, evict the oldest withpopitem(last=False).
- If
Walk-through
Capacity = 2.
| op | OrderedDict (oldest → newest) | result |
|---|---|---|
put(1, 1) | {1: 1} | — |
put(2, 2) | {1: 1, 2: 2} | — |
get(1) | {2: 2, 1: 1} (1 moved) | 1 |
put(3, 3) | inserts 3, size 3 → evict 2 → {1: 1, 3: 3} | — |
get(2) | {1: 1, 3: 3} (no change) | -1 |
put(4, 4) | size becomes 3 → evict 1 → {3: 3, 4: 4} | — |
get(1) | unchanged | -1 |
get(3) | {4: 4, 3: 3} | 3 |
get(4) | {3: 3, 4: 4} | 4 |
Edge cases
geton a missing key: return-1without touching ordering.- Updating an existing key: must move it to end and update the value. The implementation does both.
- Capacity 0: the eviction step would fire on every
put, leaving the dict empty. (Most variants of this problem guarantee capacity ≥ 1.)
Complexity
- Time:
O(1)amortized perget/put. - Space:
O(capacity)— the dict holds at mostcapacityentries.
Implementation
import java.util.*;
class LRUCache {
private int capacity;
private LinkedHashMap<Integer, Integer> map;
public LRUCache(int capacity) {
this.capacity = capacity;
this.map = new LinkedHashMap<>(capacity, 0.75f, true);
}
public int get(int key) {
if (!map.containsKey(key)) return -1;
return map.get(key);
}
public void put(int key, int value) {
map.put(key, value);
if (map.size() > capacity) {
int oldest = map.keySet().iterator().next();
map.remove(oldest);
}
}
}