Hash map alone gives O(1) lookup but no notion of "recency" — you can't tell which entry was used least recently.
Doubly-linked list alone gives O(1) head/tail insertion and deletion AND a clear order — but finding a specific key requires walking the list (O(n)).
Together: the hash map tells you where a node lives in O(1); the DLL lets you unlink and relink that node in O(1). Three operations stay O(1):
get(key) → look up node via the map, unlink it, splice in at the head.put(key, val) on existing key → same as get, plus overwrite value.put(key, val) on new key when full → drop the tail node (least recent), remove its key from the map, add the new node at head.Python's OrderedDict implements exactly this internally — you're using a prebuilt hashmap+DLL. The manual version (Node class with prev/next pointers, sentinel head/tail) is the interview follow-up if asked to do it without stdlib.