leetcode 146LRU缓存

cpp 复制代码
#include <unordered_map>
#include <list>
using namespace std;

class LRUCache {
public:
    // 缓存容量
    int capacity;

    // 双向链表
    // 每个元素存储 {key, value}
    // 链表头:最近使用
    // 链表尾:最久没使用
    list<pair<int, int>> cache;

    // 哈希表:
    // key -> key 在链表中的位置
    unordered_map<int, list<pair<int, int>>::iterator> map;

    // 构造函数
    LRUCache(int capacity) {
        this->capacity = capacity;
    }

    int get(int key) {

        // 1. key 不存在
        if (map.find(key) == map.end()) {
            return -1;
        }

        // 2. 找到 key 对应的链表节点
        auto it = map[key];

        // 3. 保存 value
        int value = it->second;

        // 4. 删除原来的节点
        cache.erase(it);

        // 5. 把它重新放到链表最前面
        // 表示这个 key 刚刚被使用了
        cache.push_front({key, value});

        // 6. 更新 map 中保存的位置
        map[key] = cache.begin();

        return value;
    }

    void put(int key, int value) {

        // 情况1:key 已经存在
        if (map.find(key) != map.end()) {

            // 找到原来的位置
            auto it = map[key];

            // 删除旧节点
            cache.erase(it);

            // 删除旧的映射
            map.erase(key);
        }

        // 情况2:
        // key 不存在,或者上面已经把旧 key 删除了
        // 判断缓存是否已经满了
        if (cache.size() == capacity) {

            // 链表最后一个就是最久没使用的元素
            auto last = cache.back();

            // last.first 就是要删除的 key
            int oldKey = last.first;

            // 删除 map 中的数据
            map.erase(oldKey);

            // 删除链表最后一个节点
            cache.pop_back();
        }

        // 把新的 key-value 放在链表最前面
        cache.push_front({key, value});

        // 保存 key 对应的链表位置
        map[key] = cache.begin();
    }
};

这道 LRU 题,最值得记的就是下面这些高频点和易错点。

  • list<pair<int,int>> cache:链表里存的是 (key, value),链表头表示最近使用,链表尾表示最久没使用。
  • unordered_map<int, list<pair<int,int>>::iterator> mapmap 的 key 是缓存 key,value 是这个 key 在链表中的位置,也就是迭代器。
  • map[key] = cache.begin();:把当前 key 和链表头节点建立对应关系。
  • auto it = map[key];:取出这个 key 对应的链表迭代器。
  • it->first:链表节点里的 key。
  • it->second:链表节点里的 value。
  • cache.back():拿到链表最后一个元素本身,所以用 last.firstlast.second
  • prev(cache.end()):拿到最后一个元素的迭代器,所以用 it->firstit->second
  • cache.end():不是最后一个元素,而是最后一个元素后面的位置,不能直接访问。
  • cache.erase(it):删除迭代器 it 指向的节点。
  • cache.push_front({key,value}):把元素放到链表头,表示"刚刚使用过"。
  • cache.pop_back():删除链表尾部,也就是最久没使用的元素。
  • map.find(key) == map.end():key 不存在。
  • map.find(key) != map.end():key 存在。
  • this->capacity = capacity:左边是类成员变量,右边是构造函数参数;同名时用 this-> 区分。

这题最容易错的地方是:删除链表节点后,原来的迭代器失效,所以必须重新更新 map[key] 例如:

复制代码
cache.erase(it);
cache.push_front({key, value});
map[key] = cache.begin();

不能只移动链表而不更新 map[key]

还有一个高频点是,容量满时要同时删两处:

复制代码
int oldKey = cache.back().first;
map.erase(oldKey);   // 删除哈希表中的记录
cache.pop_back();    // 删除链表节点

如果只删链表,不删 map,哈希表里就会留下一个失效迭代器。

最后,把整题逻辑压缩成一句话:

map 负责 O(1) 找节点,list 负责维护最近使用顺序;访问过的放头部,容量满就删尾部。

时间复杂度也是高频考点:

复制代码
get:O(1)
put:O(1)
空间复杂度:O(capacity)

你现在刷这题时,最该重点记住的 6 个操作就是:

复制代码
map.find(key)
map[key]
cache.begin()
cache.erase(it)
cache.push_front(...)
cache.pop_back()

这几个基本就是 LRU 的核心。

相关推荐
shehuiyuelaiyuehao3 分钟前
算法39,位运算,消失的两个数字
java·数据结构·算法
ZiLing4 分钟前
2026 ROS 2 Lyrical 踩坑实录(一):编译与依赖——rosdep、现代 CMake 与 CMake 4.x
算法
Murphy_lx6 分钟前
1124. 表现良好的最长时间段
c++·算法
aramae16 分钟前
模拟实现strstr函数(C语言)
c语言·开发语言·算法
liliangcsdn30 分钟前
因子权重矩阵处理-滞回缓冲带+降频稳定化动态重选
开发语言·python·算法
敲代码的嘎仔1 小时前
自己设计了一个兑换码算法:自增ID + Base32转码 + 按位加权签名 + 异或混淆,面试被追问细节时终于不用慌了
java·数据库·mysql·算法·微服务·面试·职场和发展
云析赢指标公式网42 小时前
文华WH6布林轨道均线强弱共振指标公式
前端·算法
luj_17682 小时前
一线一区一变破解人盯人防守密码
开发语言·网络·c++·经验分享·算法
Wang's Blog3 小时前
Java框架快速入门: Spring Security+OAuth2之字段验证与自定义验证注解实战
java·算法·spring
带多刺的玫瑰3 小时前
Leecode#29刷题之两数相除
java·python·算法