leetcode题解-460.LFU缓存

本文介绍了如何设计和实现最不经常使用(LFU)缓存的数据结构,包括get和put操作。通过使用map和set来维护频率和访问顺序,并在缓存满时根据LFU原则移除元素。此外,还提供了错误处理,如当缓存容量为0时不做插入操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


博客专栏地址:https://blog.youkuaiyun.com/feng964497595/category_9848847.html
github地址:https://github.com/mufeng964497595/leetcode


题目描述

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

思路解析

  1. 题目没有别的限制,就是一道简单的模拟题(不看进阶的时间复杂度O(1)的要求哈)。一开始以为是LRU,仔细看了才发现是LFU,优先抹除频率低的key,那就需要保存频率信息了。然后后面又说频率相同时要按访问时间去除key,那就需要保存访问时间了。这里用时间戳肯定不大合适,直接用个变量来记录操作序号,用这个来当作访问时间就可以了。至此,我们的数据结构体需要保存频率访问时间valuekey的话用来当索引就好了。因此用个map可以记录这些信息,用于get和put方法。
  2. put、get的步骤直接模拟照做就可以了,当缓存容量满了的时候,再插入数据要移除一个键,那么就需要对缓存的数据进行排序,把要移除的对象作为第一个,方便查找。排序的话,那就用set来存放就行了,自带排序。然后我们就会发现一个问题,移除set的第一个元素之后,上面说的map也需要移除,不然数据不一致。而map用键作为key,所以数据结构体还需要加上key
  3. put步骤还要记得判断一下key是否存在,存在的话就更新key,不存在就插入key。插入key时才需要移除set的第一个元素并移除map中对应的数据。
  4. 本来这样就结束了,然后提交代码的时候有个样例报错了,错误样例的cache容量是0 =_=||。。。所以在put操作前先判断容量是不是0,是的话直接return,啥也不做(容量0了还怎么插入)

示例代码

class LFUCache {
public:
    LFUCache(int capacity) : m_dwCapacity(capacity) {
        m_dwCurrent = 0;
        m_dwTime = 0;
    }

    int get(int key) {
        auto mit = m_mIndex.find(key);
        if (m_mIndex.end() == mit)
            return -1;

        // 找到了,更新访问频率和时间
        ++m_dwTime;
        m_setCache.erase(mit->second);
        mit->second.fre++;
        mit->second.time = m_dwTime;
        m_setCache.insert(mit->second);

        return mit->second.value;
    }

    void put(int key, int value) {
        if (0 == m_dwCapacity)
            return;

        ++m_dwTime;
        auto mit = m_mIndex.find(key);
        if (m_mIndex.end() == mit) {
            // key不存在,插入
            if (m_dwCurrent >= m_dwCapacity) {
                // 容量已满,先移除
                m_mIndex.erase(m_setCache.begin()->key);
                m_setCache.erase(m_setCache.begin());
                --m_dwCurrent;
            }

            // 插入数据
            SCacheItem item(1, m_dwTime, key, value);
            m_mIndex.insert(std::make_pair(key, item));
            m_setCache.insert(item);
            ++m_dwCurrent;
        } else {
            // key已存在,更新访问频率、时间和值
            m_setCache.erase(mit->second);
            mit->second.fre++;
            mit->second.time = m_dwTime;
            mit->second.value = value;
            m_setCache.insert(mit->second);
        }
    }

private:
    struct SCacheItem {
        int fre;        // 访问频率
        int time;       // 访问时间
        int key;        // 缓存保留的key
        int value;      // 缓存保留的值

        SCacheItem(int f = 0, int t = 0, int k = -1, int v = -1) : fre(f), time(t), key(k), value(v) {
        }

        bool operator < (const SCacheItem& item) const {
            if (fre == item.fre)
                return time < item.time;
            return fre < item.fre;
        }
    };

private:
    std::unordered_map<int, SCacheItem> m_mIndex;    // 索引
    std::set<SCacheItem> m_setCache;    // 缓存体
    int m_dwCapacity;       // 容量
    int m_dwCurrent;        // 当前数量
    int m_dwTime;           // 充当访问时间
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值