[Leetcode] LRU Cache (python)
LRU: it has not been used for a long time. To obtain the latest and longest information, a policy is required for record. If a field similar to the timestamp type is added, time information can be obtained through traversal or sorted by timestamp. However, additional maintenance is required, and the maintenance cost is high.
A widely used strategy is to use dual-end queues at the underlying layer for maintenance. The dual-end queue makes the operation easier during insertion and deletion. However, it does not seem sufficient to use a dual-end queue. For example, in get, the given key parameters need to be queried sequentially, so in order) time to obtain the key requires a hash-like structure. In python, the dictionary is used.
The next thing is, what information are stored in the dictionary and double-end queue?
class dqNode:def __init__(self, key, val):self.val = valself.key = keyself.pre = Noneself.next = None
Dictionary: <key: dqnode>
In this way, we can quickly find the node corresponding to the key through the dictionary and find the value information from the node.
In this way, after the get or set operation is performed on a key, we move the corresponding dqnode to the head of the dual-end queue, indicating that the node was recently accessed, those at the end of the team were not recently accessed, or the last visit was the longest. Here we can see if we can set only the val sub-segment in dqnode, because the key information is available in the dictionary. This is not possible considering the deletion, because we can easily Delete the dqnode node at the end of the team, we can't do anything to delete the corresponding items in the dictionary, because the dictionary search is based on the key, so the key should also be stored in the dqnode.
To facilitate the operation, we still need to set a pseudo-head knot and a pseudo-tail node.
class LRUCache: # @param capacity, an integerdef __init__( self, capacity ):self.capacity = capacityself.curSize = 0self.keys2valNode = { } # mapping key to the node that has the value info# dqlist to store
pairsself.head = dqNode(-1, -1)self.tail = dqNode(-1, -1)self.head.next = self.tailself.tail.pre = self.head
Variable description:
Keys2valNode: a dictionary container. The key is the key, and the corresponding val is the dqnode node where the storage val is located.
Head and tail: head and tail pointer of a dual-end queue
class dqNode:def __init__(self, key, val):self.val = valself.key = keyself.pre = Noneself.next = Noneclass LRUCache: # @param capacity, an integerdef __init__( self, capacity ):self.capacity = capacityself.curSize = 0self.keys2valNode = { } # mapping key to the node that has the value info# dqlist to store
pairsself.head = dqNode(-1, -1)self.tail = dqNode(-1, -1)self.head.next = self.tailself.tail.pre = self.head# util functions def moveToFirst( self, pnode ):# link pnode.pre and pnode.nextif pnode.pre:pnode.pre.next = pnode.nextif pnode.next:pnode.next.pre = pnode.pre# move pnode to firstpnode.next = self.head.nextif self.head.next:self.head.next.pre = pnodeself.head.next = pnodepnode.pre = self.headdef removeLRU( self ):pdel = self.tail.prepdel.pre.next = self.tailself.tail.pre = pdel.predel self.keys2valNode[ pdel.key ]del pdeldef Insert( self, key, value ):newNode = dqNode(key, value)# add to dictself.keys2valNode[ key ] = newNode# insert to first of dqueueself.moveToFirst(newNode)# @return an integerdef get(self, key):if self.keys2valNode.has_key(key):# get the node that has value info.pvalue = self.keys2valNode[ key ]value = pvalue.val# change pvalue to be recently visited oneself.moveToFirst( pvalue )return valueelse: return -1 # @param key, an integer # @param value, an integer # @return nothingdef set( self, key, value ):# if has key, just have to change the valueif self.keys2valNode.has_key( key ):self.keys2valNode[ key ].val = valueself.moveToFirst( self.keys2valNode[ key ] )# insert a new key# 1) curSize < capacity, just insert# 2) curSize == capacity, remove LRU and insertelse:self.Insert(key, value)if self.curSize < self.capacity:self.curSize += 1else:self.removeLRU()