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]);
        }
    }
};
相关推荐
2401_872418781 小时前
算法入门:数据结构-堆
数据结构·算法
xwz小王子2 小时前
手术机器人登上Science Robotics:2毫米纤细手臂,从3厘米切口完成腰椎神经减压
算法·机器人
黎阳之光3 小时前
视频孪生智护供水生命线:黎阳之光赋能医疗与园区水务高质量升级
运维·物联网·算法·安全·数字孪生
Black蜡笔小新4 小时前
自动化AI算法训练服务器DLTM制造业AI质检工作站助力制造业实现AI智检
人工智能·算法·自动化
嵌入式小能手4 小时前
飞凌嵌入式ElfBoard-进程间的通信之命名管道
linux·服务器·算法
啦哈拉哈4 小时前
Leetcode题解记录-hot100(81-100)
算法·leetcode·职场和发展
csdn_aspnet5 小时前
Java 霍尔分区算法(Hoare‘s Partition Algorithm)
java·开发语言·算法
诸葛务农5 小时前
道路行驶条件下电动汽车永磁电机的有效使用寿命及永磁体的失效和回收再利用(下)
java·开发语言·算法
snow@li5 小时前
AI:理解 大数据、算法、算力、电力、生成式AI、token 之间的关系
大数据·人工智能·算法
小智老师PMP5 小时前
零基础能不能考PMP?零基础专属学习路径+全套扶持体系
学习·算法·职场和发展·软件工程·求职招聘·敏捷流程