每日一题,每日一练21.LFU缓存,(我看的懂题解的每一块,但连起来我就不懂了)

  1. LFU缓存 设计并实现最不经常使用(LFU)缓存的数据结构。它应该支持以下操作:get 和 put。

get(key) - 如果键存在于缓存中,则获取键的值(总是正数),否则返回 -1。 put(key, value) -
如果键不存在,请设置或插入值。当缓存达到其容量时,它应该在插入新项目之前,使最不经常使用的项目无效。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,最近最少使用的键将被去除。

一个项目的使用次数就是该项目被插入后对其调用 get 和 put 函数的次数之和。使用次数会在对应项目被移除后置为 0。

进阶: 你是否可以在 O(1) 时间复杂度内执行两项操作?

示例:

LFUCache cache = new LFUCache( 2 /* capacity (缓存容量) */ );

cache.put(1, 1); cache.put(2, 2); cache.get(1); // 返回 1
cache.put(3, 3); // 去除 key 2 cache.get(2); // 返回 -1 (未找到key 2)
cache.get(3); // 返回 3 cache.put(4, 4); // 去除 key 1
cache.get(1); // 返回 -1 (未找到 key 1) cache.get(3); // 返回 3
cache.get(4); // 返回 4

这题,,,,,实在不适合一个刚从周赛打完脑子还不清醒的菜鸡TWT,看了俩小时没找到从哪下手,问题在于如果用队列模拟活动顺序的话,索引需要不停的更换,如果用计数找最小值的话,会导致同值无法判断先后,因此把官方题解先拿来,有时候再细说这道题

class Node:
    def __init__(self, key, val, pre=None, nex=None, freq=0):#这里是创建链表结构的初始化
        self.pre = pre
        self.nex = nex
        self.freq = freq
        self.val = val
        self.key = key
        
    def insert(self, nex)#创建插入方法
        nex.pre = self
        nex.nex = self.nex
        self.nex.pre = nex
        self.nex = nex
    
def create_linked_list():#建立一个空链表
    head = Node(0, 0)
    tail = Node(0, 0)
    head.nex = tail
    tail.pre = head
    return (head, tail)

class LFUCache:
    def __init__(self, capacity: int):#题目初始化
        self.capacity = capacity
        self.size = 0
        self.minFreq = 0
        self.freqMap = collections.defaultdict(create_linked_list)
        self.keyMap = {}

    def delete(self, node):#删除链表中的方法
        if node.pre:
            node.pre.nex = node.nex
            node.nex.pre = node.pre
            if node.pre is self.freqMap[node.freq][0] and node.nex is self.freqMap[node.freq][-1]:
                self.freqMap.pop(node.freq)
        return node.key
        
    def increase(self, node):#插入链表方法
        node.freq += 1
        self.delete(node)
        self.freqMap[node.freq][-1].pre.insert(node)
        if node.freq == 1:
            self.minFreq = 1
        elif self.minFreq == node.freq - 1:
            head, tail = self.freqMap[node.freq - 1]
            if head.nex is tail:
                self.minFreq = node.freq

    def get(self, key: int) -> int:#获得时队列表进行循环移动
        if key in self.keyMap:
            self.increase(self.keyMap[key])
            return self.keyMap[key].val
        return -1

    def put(self, key: int, value: int) -> None:#新元素进入时列表是否进行删除
        if self.capacity != 0:
            if key in self.keyMap:
                node = self.keyMap[key]
                node.val = value
            else:
                node = Node(key, value)
                self.keyMap[key] = node
                self.size += 1
            if self.size > self.capacity:
                self.size -= 1
                deleted = self.delete(self.freqMap[self.minFreq][0].nex)
                self.keyMap.pop(deleted)
            self.increase(node)
#作者:LeetCode-Solution
#链接:https://leetcode-cn.com/problems/lfu-cache/solution/lfuhuan-cun-by-leetcode-solution/#
#来源:力扣(LeetCode)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个 Python 实现的 LFU 缓存: ```python from collections import defaultdict class LFUCache: def __init__(self, capacity): self.capacity = capacity self.cache = {} self.freq = defaultdict(OrderedDict) self.min_freq = 0 def get(self, key): if key not in self.cache: return -1 value, freq = self.cache[key] self.freq[freq].pop(key) if len(self.freq[freq]) == 0: self.freq.pop(freq) if self.min_freq == freq: self.min_freq += 1 self.freq[freq+1][key] = value self.cache[key] = (value, freq+1) return value def put(self, key, value): if self.capacity == 0: return if key in self.cache: self.cache[key] = (value, self.cache[key][1]) self.get(key) return if len(self.cache) == self.capacity: k, v = self.freq[self.min_freq].popitem(last=False) self.cache.pop(k) self.cache[key] = (value, 1) self.freq[1][key] = value self.min_freq = 1 ``` 该实现中,LFU 缓存使用了一个字典 `cache` 来存储 key-value 对,使用一个字典 `freq` 来记录每个频次对应的 key-value 对,使用变量 `min_freq` 来记录当前最小的频次。 在 `get` 方法中,如果 key 不存在于 `cache` 中,则返回 -1。否则,将 key 对应的 value 和频次从 `freq` 中删除,如果该频次对应的 key-value 对已经为空,则将该频次从 `freq` 中删除,并更新 `min_freq`。然后,将 key 对应的 value 和频次加一后添加到 `freq` 中,并更新 `cache` 中的 key-value 对。 在 `put` 方法中,如果 `capacity` 为 0,则直接返回。如果 key 已存在于 `cache` 中,则将 `cache` 中的 key-value 对更新,并调用 `get` 方法以更新 `freq` 和 `min_freq`。如果 `cache` 已经满了,则从 `freq` 中删除当前最小频次的 key-value 对,并从 `cache` 中删除对应的 key-value 对。然后,将新的 key-value 对添加到 `cache` 和 `freq` 中,并将 `min_freq` 设置为 1。 使用示例: ```python cache = LFUCache(2) cache.put(1, 1) cache.put(2, 2) assert cache.get(1) == 1 cache.put(3, 3) assert cache.get(2) == -1 assert cache.get(3) == 3 cache.put(4, 4) assert cache.get(1) == -1 assert cache.get(3) == 3 assert cache.get(4) == 4 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值