LRU Cache
Defining two helper functions r e m o v e remove re m o v e and a d d add a dd makes this question a lot easier. We use a hashmap to store k e y → n o d e key\to node k ey → n o d e to have the g e t ( ) get() g e t ( ) function be O ( 1 ) O(1) O ( 1 ) time. The p u t ( ) put() p u t ( ) can be done in O ( 1 ) O(1) O ( 1 ) by making the tail represent our MRU and head be the LRU.
class Node :
def __init__ ( self , key , val ) :
self . key = key
self . val = val
self . prev = None
self . next = None
class LRUCache :
def __init__ ( self , capacity : int ) :
self . capacity = capacity
self . node_map = { }
self . head = Node ( - 1 , - 1 ) # LRU
self . tail = Node ( - 1 , - 1 ) # MRU
self . head . next = self . tail
self . tail . prev = self . head
def _add ( self , node ) :
tail = self . tail . prev
tail . next = node
node . prev = tail
node . next = self . tail
self . tail . prev = node
def _remove ( self , node ) :
node . prev . next = node . next
node . next . prev = node . prev
def get ( self , key : int ) - > int :
if key not in self . node_map :
return - 1
# move the found key to the tail of DLL
node = self . node_map [ key ]
self . _remove ( node )
self . _add ( node )
return node . val
def put ( self , key : int , value : int ) - > None :
if key in self . node_map :
old = self . node_map [ key ]
self . _remove ( old )
node = Node ( key , value )
self . node_map [ key ] = node
self . _add ( node )
if len ( self . node_map ) > self . capacity :
head = self . head . next
self . _remove ( head )
del self . node_map [ head . key ]