力扣hot100——LRU缓存(面试高频考题)

请你设计并实现一个满足 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) 的平均时间复杂度运行。

解题思路:

根据lru特性,使用哈希表+双向链表

哈希表用于查找存储区中的节点信息

双向链表:存储整个节点,由于是最久未使用页面删除,可以使用使用双向列表,最近的存储到前面,这样慢慢的就会按使用频率2(时间)将节点存储起来,每次只需要将链尾删除就行;

cpp 复制代码
class LRUCache {
    // 经典实现;数据结构采用 双向链表+哈希表
    // 加入新节点就加到头,表示最新
    // 删除时就删除尾节点,就是很久不用的
    
// 双向链表结构
struct DlistNode{
    int key,val; 
    DlistNode *pre,*next; // pre指向前一个节点,next 指向后一个节点
    DlistNode() : key(-1),val(-1),pre(nullptr),next(nullptr) {}// 默认构造
    DlistNode(int _key,int _val) : key(_key),val(_val),pre(nullptr),next(nullptr) {} // 输入数据构造
};
private:
    unordered_map<int,DlistNode*> LRU_map; 
    DlistNode* head; // 头
    DlistNode* tail; // 尾
    int cap_limit; // 内存限制
public:
    LRUCache(int capacity) {
        cap_limit = capacity;
        LRU_map.clear();
        // 声明一个哑节点;用于建立后面的节点链表
        head = new DlistNode();
        tail = new DlistNode();
        head->next = tail;
        tail->next = head;
    }
    
    int get(int key) {  // 如果有再次使用则要放到最前面,再次启用
        if(LRU_map.count(key)){
            int newval = LRU_map[key]->val;
            delNode(key);
            addNode(key,newval);
            return newval;
        }
        return -1;
    }
    
    void put(int key, int value) {
        if(LRU_map.count(key)){
            delNode(key);
            addNode(key,value);
        }
        else{
            if(LRU_map.size() == cap_limit){
                delNode(tail->pre->key);  // 满了之后将最久未用的删除
                addNode(key,value);
            }
            else{
                addNode(key,value);
            }
        }
    }

    // 增加节点 (头插)
    void addNode(int key,int val){
        if(LRU_map.count(key)){  // 已经存在不增加节点
            return;
        }
        DlistNode *cur = new DlistNode(key,val);
        // 头插入 
        cur->next = head->next;
        head->next->pre = cur;
        cur->pre = head;
        head->next = cur;

        // 哈希表插入
        LRU_map[key] = cur;
    }

    // 删除节点
    void delNode(int key){
        if(!LRU_map.count(key)){  // 已经存在不增加节点
            return;
        }
        DlistNode *cur = LRU_map[key]; // 找到要删除的节点
        LRU_map.erase(key); // 删除哈希表中这个间
        
        DlistNode *front = cur->pre, *back = cur->next;
        front->next = back;
        back->pre = front;
        cur->pre = nullptr;
        cur->next = nullptr;
    }

};

/**
 * 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);
 */
相关推荐
Musennn13 分钟前
leetcode 15.三数之和 思路分析
算法·leetcode·职场和发展
?abc!4 小时前
缓存(3):本地缓存作用 及 数据一致性 实现策略
缓存
MarkHard1235 小时前
Leetcode (力扣)做题记录 hot100(62,64,287,108)
算法·leetcode·职场和发展
大学生小郑7 小时前
Go语言八股之Mysql基础详解
mysql·面试
Toky Zhu8 小时前
ubuntu清除缓存
linux·ubuntu·缓存
呦呦鹿鸣Rzh8 小时前
redis
数据库·redis·缓存
只因只因爆9 小时前
spark的缓存
大数据·缓存·spark
摘星编程9 小时前
Redis+Caffeine构建高性能二级缓存
数据库·redis·缓存
酷爱码10 小时前
Nginx的核心功能--正向代理、反向代理、缓存和Rewrite
运维·nginx·缓存
hello_ejb310 小时前
聊聊JetCache的缓存构建
java·前端·缓存