Leetcode 146. LRU Cache + 460. LFU Cache 原理及代碼實現

一:LRU Cache原理

詳細請見鏈接:https://www.jianshu.com/p/74a4efacb0a7

二:Python實現

class LinkedNode(object):
    def __init__(self, key, val): # 節點需要保存key,val
        self.key = key
        self.val = val
        self.next = None
        self.pre = None


class LRUCache(object):
    def __init__(self, capacity):
        self.capacity = capacity
        self.hashMap = collections.defaultdict(LinkedNode)  # key:LinkedNode
        
        self.head = LinkedNode(-1, -1)  
        self.tail = LinkedNode(-2, -2)  
        self.head.next = self.tail
        self.tail.pre = self.head

    def get(self, key): # 判斷緩存中是否存在? 修改訪問順序
        """
        通過 HashMap 找到雙向鏈表節點,
        因爲根據LRU 原理,這個節點是最新訪問的,所以要把節點插入到隊頭,然後返回緩存的值.
        """
        
        res = -1
        if key in self.hashMap.keys():
            curNode = self.hashMap[key]
            res = curNode.val
            # 修改訪問順序
            self._remove(curNode)
            self._add(curNode)
        
        return res

    def put(self, key, value): # 判斷緩存空間是否滿了? key爲訪問的序號
        """
        首先在 HashMap 找到 Key 對應的節點,如果節點存在,更新節點的值,並把這個節點移動隊頭。
        如果不存在,需要構造新的節點,並且嘗試把節點塞到隊頭,
        如果LRU空間不足,則通過 tail 淘汰掉隊尾的節點,同時在 HashMap 中移除 Key
        """
         
        # 已經存在這個key了, 刪了這個結點
        if key in self.hashMap.keys():
            self._remove(self.hashMap[key])
        
        
        # 插入新節點, 這裏其實就已經更新順序了
        curNode = LinkedNode(key, value)
        self._add(curNode)
        self.hashMap[key] = curNode # 加入hashMap中
        
        # 滿了要刪了尾結點
        if len(self.hashMap) > self.capacity:
            last = self.tail.pre
            self.hashMap.pop(last.key)  # 刪除的是尾結點的key,不是插入節點的key啊
            self._remove(last)
           
    
    def _remove(self, node): # 刪除
        p = node.pre
        n = node.next
        p.next = n
        n.pre = p

    def _add(self, node):  # 插入到頭結點之後
        p = self.head.next
        p.pre = node
        node.next = p
        self.head.next = node
        node.pre = self.head

三:LFU Cache原理

參考:https://leetcode.com/problems/lfu-cache/discuss/207673/Python-concise-solution-detailed-explanation%3A-Two-dict-%2B-Doubly-linked-list

四:python實現

class Node:
    def __init__(self, key, val):
        self.key = key
        self.val = val
        self.freq = 1
        self.prev = self.next = None
        
class DLinkedList:
    def __init__(self):
        self._sentinel = Node(None, None) # dummy node
        self._sentinel.next = self._sentinel.prev = self._sentinel
        self._size = 0
    
    def __len__(self):
        return self._size
    
    def append(self, node):
        node.next = self._sentinel.next
        node.prev = self._sentinel
        node.next.prev = node
        self._sentinel.next = node
        self._size += 1
    
    def pop(self, node=None):
        if self._size == 0:
            return
        
        if not node:
            node = self._sentinel.prev

        node.prev.next = node.next
        node.next.prev = node.prev
        self._size -= 1
        
        return node

class LFUCache(object):

    def __init__(self, capacity):
        self._size = 0
        self._capacity = capacity
        
        self._node = dict() # key: Node
        self._freq = collections.defaultdict(DLinkedList)
        self._minfreq = 0
        
    def _update(self, node):
        freq = node.freq
        
        self._freq[freq].pop(node)
        if self._minfreq == freq and not self._freq[freq]:
            self._minfreq += 1
        
        node.freq += 1
        freq = node.freq
        self._freq[freq].append(node)
        
    def get(self, key):
        if key not in self._node:
            return -1
        
        node = self._node[key]
        self._update(node)
        return node.val

    def put(self, key, value):
        if self._capacity == 0:
            return
        
        if key in self._node:
            node = self._node[key]
            self._update(node)
            node.val = value
        else:
            if self._size == self._capacity:
                node = self._freq[self._minfreq].pop()
                del self._node[node.key]
                self._size -= 1
                
            node = Node(key, value)
            self._node[key] = node
            self._freq[1].append(node)
            self._minfreq = 1
            self._size += 1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章