35 LRU缓存

LRU缓存

    • [题解1 双map(差2个testcases)](#题解1 双map(差2个testcases))
    • [题解2 哈希表+双向链表(参考)](#题解2 哈希表+双向链表(参考))
    • [题解3 STL:list+unordered_map](#题解3 STL:list+unordered_map)

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 getput 必须以 O(1) 的平均时间复杂度运行。

提示:

  • 1 <= capacity <= 3000
  • 0 <= key <= 10000
  • 0 <= value <= 105
  • 最多调用 2 ∗ 1 0 5 2 * 10^5 2∗105 次 getput

题解1 双map(差2个testcases)

cpp 复制代码
class LRUCache {
    int LRUcapacity;
    map<int, int> cacheMap;
    map<int, int> usecases;
    int time = 0; 
    static bool cmp(const pair<int, int>& lhs, const pair<int, int>& rhs) {  
        return lhs.second < rhs.second;  
    }  
    
public:
    LRUCache(int capacity) {
        LRUcapacity = capacity;
    }
    
    int get(int key) {
        if(cacheMap.count(key)){
        // 记录访问时刻(value越大代表最近使用)
            usecases[key] = time++;
            return cacheMap[key];
        }
        else return -1;
    }
    
    void put(int key, int value) {
        if(cacheMap.count(key)){
            cacheMap[key] = value;
            usecases[key] = time++;
        }else{
        // 没满足O(1)的时间复杂度
            if(cacheMap.size() + 1 > LRUcapacity){
                // 拿到最早访问的关键字 value最小
                vector<pair<int, int>> usecasesVector(usecases.begin(), usecases.end());
                sort(usecasesVector.begin(), usecasesVector.end(), cmp);
                int idx = usecasesVector[0].first;
                cacheMap.erase(cacheMap.find(idx));
                usecases.erase(usecases.find(idx));
            }
            cacheMap[key] = value;
            usecases[key] = time++;
        }
            
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */

题解2 哈希表+双向链表(参考)

cpp 复制代码
class LRUCache {
    int LRUcapacity;
    // 双向链表保证每次找最近使用的操作时间复杂度为O(1)
    struct Node{
        int key;
        int value;
        Node* prev;
        Node* next;
        Node(): key(0), value(0), prev(nullptr), next(nullptr){}
        Node(int key1, int value1): key(key1), value(value1), prev(nullptr), next(nullptr){}
    };
    map<int, Node*> cacheMap;
    Node* head, *tail;
public:
    LRUCache(int capacity) {
        LRUcapacity = capacity;
        head = new Node();
        tail = new Node();
        head->next = tail;
        tail->prev = head;
    }
    
    int get(int key) {
        if(cacheMap.count(key)){
            // 把node添加到头结点H
            // 对于双向链表, 原位置node需要修正的:
            // node->next->prev 和 node->prev->next
            // 目标位置H需要修正的:
            // H->next, H->next->prev
            Node* getNode = cacheMap[key];

            getNode->prev->next = getNode->next;
            getNode->next->prev = getNode->prev;

            getNode->prev = head;
            getNode->next = head->next;

            head->next = head->next->prev = getNode;

            return getNode->value;
        }
        else return -1;
    }
    
    void put(int key, int value) {
        if(cacheMap.count(key)){
            
            Node* getNode = cacheMap[key];
            getNode->value = value;
            
            // 添加到头结点
            getNode->prev->next = getNode->next;
            getNode->next->prev = getNode->prev;

            getNode->prev = head;
            getNode->next = head->next;

            head->next = head->next->prev = getNode;

        }else{
            if(cacheMap.size() + 1 > LRUcapacity){
                Node* pre = tail->prev;
                cacheMap.erase(cacheMap.find(pre->key));
                pre->prev->next = pre->next;
                pre->next->prev = pre->prev;
                // 防止内存泄漏
                delete pre;
                
            }
            cacheMap[key] = new Node(key, value);

            Node* getNode = cacheMap[key];
            // 新结点添加到头结点 (代表最近被使用)
            // 新结点无原位置,所以只需要修改H附近的链
            getNode->prev = head;
            getNode->next = head->next;

            head->next = head->next->prev = getNode;
        }
            
    }
};

题解3 STL:list+unordered_map

cpp 复制代码
class LRUCache {
    const int cap;
    list<pair<int, int>> cache;
    unordered_map<int, decltype(cache.begin())> dict;
public:
    LRUCache(int capacity) : cap(capacity) {}
    
    int get(int key) {
        if (!dict.count(key))
            return -1;
        cache.splice(cache.cend(), cache, dict[key]);
        return dict[key]->second;
    }
    
    void put(int key, int value) {
        if (!dict.count(key)) {
            if (cache.size() == cap) {
                dict.erase(cache.front().first);
                cache.pop_front();
            }

            dict[key] = cache.emplace(cache.cend(), key, value);
        }
        else {
            dict[key]->second = value;
            cache.splice(cache.cend(), cache, dict[key]);
        }
    }
};
相关推荐
bkspiderx33 分钟前
C++经典的数据结构与算法之经典算法思想:贪心算法(Greedy)
数据结构·c++·算法·贪心算法
中华小当家呐2 小时前
算法之常见八大排序
数据结构·算法·排序算法
沐怡旸2 小时前
【算法--链表】114.二叉树展开为链表--通俗讲解
算法·面试
tju新生代魔迷3 小时前
数据结构:双向链表
数据结构·链表
一只懒洋洋3 小时前
K-meas 聚类、KNN算法、决策树、随机森林
算法·决策树·聚类
方案开发PCBA抄板芯片解密4 小时前
什么是算法:高效解决问题的逻辑框架
算法
songx_994 小时前
leetcode9(跳跃游戏)
数据结构·算法·游戏
学c语言的枫子4 小时前
数据结构——双向链表
c语言·数据结构·链表
小白狮ww4 小时前
RStudio 教程:以抑郁量表测评数据分析为例
人工智能·算法·机器学习
AAA修煤气灶刘哥5 小时前
接口又被冲崩了?Sentinel 这 4 种限流算法,帮你守住后端『流量安全阀』
后端·算法·spring cloud