相关题目:
460. LFU 缓存

相关文章
LRU 缓存 – 哈希链表

# 460. LFU 缓存
# Python中和 LinkedHashSet 相似的数据结构 OrderedDict
from collections import OrderedDict
class LFUCache:
    # key 到 val 的映射,我们后文称为 KV 表
    keyToVal = {}
    # key 到 freq 的映射,我们后文称为 KF 表
    keyToFreq = {}
    # freq 到 key 列表的映射,我们后文称为 FK 表
    freqToKeys = {}
    # 记录最小的频次
    minFreq = 0
    # 记录 LFU 缓存的最大容量
    cap = 0

    def __init__(self, capacity: int):
        self.keyToVal = {}
        self.keyToFreq = {}
        self.freqToKeys = {}
        self.cap = capacity
        self.minFreq = 0

    def get(self, key: int) -> int:
        if key not in self.keyToVal:
            return -1
        # 增加 key 对应的 freq
        self.increaseFreq(key)
        return self.keyToVal[key]

    def put(self, key: int, val: int) -> None:
        if self.cap <= 0:
            return

        # 若 key 已存在,修改对应的 val 即可
        if key in self.keyToVal:
            self.keyToVal[key] = val
            # key 对应的 freq 加一
            self.increaseFreq(key)
            return

        # key 不存在,需要插入
        # 容量已满的话需要淘汰一个 freq 最小的 key
        if self.cap <= len(self.keyToVal):
            self.removeMinFreqKey()

        # 插入 key 和 val,对应的 freq 为 1
        # 插入 KV 表
        self.keyToVal[key] = val
        # 插入 KF 表
        self.keyToFreq[key] = 1
        # 插入 FK 表
        self.freqToKeys.setdefault(1, OrderedDict())
        self.freqToKeys[1].setdefault(key)
        # 插入新 key 后最小的 freq 肯定是 1
        self.minFreq = 1

    def removeMinFreqKey(self):
        # freq 最小的 key 列表
        keyList = self.freqToKeys.get(self.minFreq)
        # 其中最先被插入的那个 key 就是该被淘汰的 key
        deletedKey = next(iter(keyList))
        # 更新 FK 表
        keyList.pop(deletedKey)
        if not keyList:
            self.freqToKeys.pop(self.minFreq)
            # 问:这里需要更新 minFreq 的值吗?
        # 更新 KV 表
        self.keyToVal.pop(deletedKey)
        # 更新 KF 表
        self.keyToFreq.pop(deletedKey)

    def increaseFreq(self, key: int) -> None:
        freq = self.keyToFreq[key]
        # 更新 KF 表
        self.keyToFreq[key] = freq + 1
        # 更新 FK 表
        # 将 key 从 freq 对应的列表中删除
        self.freqToKeys[freq].pop(key)
        # 将 key 加入 freq + 1 对应的列表中
        self.freqToKeys.setdefault(freq + 1, OrderedDict())
        self.freqToKeys[freq + 1].setdefault(key)
        # 如果 freq 对应的列表空了,移除这个 freq
        if not self.freqToKeys[freq]:
            del self.freqToKeys[freq]
            # 如果这个 freq 恰好是 minFreq,更新 minFreq
            if freq == self.minFreq:
                self.minFreq += 1


10-08 13:06