メモやらログやら

考えたこととかメモする

LRU Cache

class ListNode(object):
    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.head = ListNode(-1, -1) # 新しいほう
        self.tail = ListNode(-2,-2) # 古いほう
        self.cache = dict() # nodeがval
        self.head.next = self.tail
        self.tail.prev = self.head
        self.capacity = capacity
        self.length = 0
        
        
    # 先頭にnodeを追加
    def add(self, node):
        
        node.prev = self.head
        node.next = self.head.next
        self.head.next = node
        node.next.prev = node
        
    # 削除
    def remove(self, node):
        node.prev.next, node.next.prev = node.next, node.prev

    # 一回削除してから先頭に足す。増えないのでcapacityを超えることはない
    def get(self, key: int) -> int:
        if key not in self.cache:
            return -1
        
        node = self.cache[key]
        self.remove(node)
        self.add(node)
        return node.val
        

    def put(self, key: int, value: int) -> None:
        # 既にキャッシュ内に存在するならgetとほぼ同じ
        if key in self.cache:
            node = self.cache[key]
            node.val = value
            self.remove(node)
            self.add(node)
        # ないならcapacityを超える場合はtailに最も近いものを削除してから追加
        else:
            if len(self.cache) == self.capacity:
                tail_node = self.tail.prev
                del self.cache[tail_node.key]
                self.remove(tail_node)
            
            node = ListNode(key, value)
            self.cache[key] = node
            self.add(node)

collections.OrderedDictを使うと非常にスッキリする

class LRUCache:

    def __init__(self, capacity: int):
        self.capacity = capacity
        self.dic = collections.OrderedDict()
        
    
    def get(self, key):
        if key not in self.dic:
            return -1
        
        val = self.dic[key]
        self.dic.move_to_end(key) # 後ろのものほど新しい
        return val
    

    def put(self, key, value):
        self.dic[key] = value
        self.dic.move_to_end(key)
        if len(self.dic) > self.capacity:
            # last=Trueなら末尾(最も新しく利用したもの)を、Falseなら先頭のkey,valueを削除
            self.dic.popitem(last=False)


参考
medium.com

leetcode.com