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> map:map 的 key 是缓存 key,value 是这个 key 在链表中的位置,也就是迭代器。
  • map[key] = cache.begin();:把当前 key 和链表头节点建立对应关系。
  • auto it = map[key];:取出这个 key 对应的链表迭代器。
  • it->first:链表节点里的 key。
  • it->second:链表节点里的 value。
  • cache.back():拿到链表最后一个元素本身,所以用 last.first、last.second。
  • prev(cache.end()):拿到最后一个元素的迭代器,所以用 it->first、it->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 的核心。

相关推荐
小蒋学算法7 小时前
算法-交替删除操作后最后剩下的整数-跟着灵茶山艾府学算法
数据结构·算法
荆棘鸟智能7 小时前
林业遥感长势评估怎么做?从NDVI时序分析到LiDAR蓄积量回归
人工智能·算法·智慧林业
hweiyu008 小时前
Redis命令:HMGET
redis·缓存
hhb_6188 小时前
AIRAGDebug:一键定位RAG链路异常
人工智能·python·算法
朝朝辞暮i8 小时前
C++ 第 6 课:switch —— 多状态选择
开发语言·c++·算法
苏打豆9 小时前
Pinocchio源码阅读——刚体运动物理量空间变换及求导
c++·线性代数·算法·矩阵·机器人
FluxArt9 小时前
GPT Image 2.5 中文提示词教程:Flux Art 可复用模板
前端·gpt·算法
思麟呀9 小时前
位运算:从一个整数到一个集合
c语言·数据结构·c++·算法
阜阳山君GEO10 小时前
豆包 SEED 新版本 GEO 优化:信源金字塔、打分体系与避坑落地指南
人工智能·算法
晓天衡宇•评测社区10 小时前
晓天衡宇亮相 2026 云栖大会:迈向更可信的高质量评测
人工智能·算法·机器学习