力扣146 - LRU缓存

视频讲解

哈希 + 双向链表

为什么要用双向链表?

快速删除节点(O(1))

如果是单链表的话,删除一个节点时,需要从头遍历,找到前驱节点 ,才能修改 prev->next,导致 O(n) 的时间复杂度

双向链表存储了两个指针,一个指针指向下一个节点,另一个指针指向上一个节点(前驱指针)。所以我们可以根据前驱指针快速找到上一个节点,然后移除掉当前节点。

demo:

cpp 复制代码
class LRUCache {
public:
    struct Node{
        int key,val;
        Node *prev,*next;
        Node(int k,int v) : key(k) , val(v) , prev(nullptr) , next(nullptr){}
    };
    map<int,Node*>mp;
    Node *L,*R; //双哨兵
    int n; //LRU的总数

    //创建操作
    LRUCache(int capacity) {
        n = capacity;
        L = new Node(-1,-1);
        R = new Node(-1,-1);
        L->next = R;
        R->prev = L;
    }

    //获取值操作 (获得值的时候需要注意:如果有值存在哈希表中的话,那么就要将这个值放在最新的地方)
    //比如: L | 2 1 4 | R 
    //我们查询1这个数,那么查完后需要变成: L | 2 4 1 | R 
    int get(int key) {
        if(mp.count(key)){
            Node* node = mp[key];
            remove(node); //在链表中移除该节点 通过双向指针移除
            insert(node->key,node->val); // 在链表中插入该节点
            return node->val;
        }else{
            return -1;
        }
    }
    
    //插入操作
    void put(int key, int value) {
        if(mp.count(key)){
            Node* node = mp[key];
            remove(node);
            insert(key,value); //这里需要用给的key和value而不是node->key和node->val(因为可能插入的是新的值)
        }else{
            if(mp.size() == n){
                Node* node = L->next; //满了,需要移除的节点
                remove(node);
                insert(key,value);
            }else{
                insert(key,value);
            }
        }
    }

    //以下为自定义新增函数 remove是移除节点的函数 insert是插入节点的函数

    //同时在链表和哈希表中删除node
    void remove(Node* node){
        Node* pre = node->prev;
        Node* nxt = node->next;
        pre->next = nxt;
        nxt->prev = pre;
        mp.erase(node->key);
    }

    //同样要同时操作链表和哈希表
    void insert(int key,int val){
        Node* node = new Node(key,val);
        Node* pre = R->prev;//这里是最后一个插入的数

        //向右
        pre->next = node;
        node->next = R;

        //向左
        node->prev = pre;
        R->prev = node;

        mp[key] = node;
    }

};

/**
 * 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);
 */
相关推荐
期待のcode33 分钟前
MyBatis框架—延迟加载与多级缓存
java·数据库·后端·缓存·mybatis
这是谁的博客?1 小时前
LangChain第三页【操作指南】_【如何缓存对话模型响应】翻译完成
缓存·langchain
_不会dp不改名_2 小时前
leetcode_146 LRU缓存
算法·leetcode·缓存
执键行天涯2 小时前
idea中已经被git缓存追踪的文件,如何让git重新忽略
git·缓存·intellij-idea
麦兜*2 小时前
Redis 7.0 新特性深度解读:迈向生产级的新纪元
java·数据库·spring boot·redis·spring·spring cloud·缓存
坐吃山猪4 小时前
Redis03-缓存知识点
redis·缓存
自信的小螺丝钉10 小时前
Leetcode 146. LRU 缓存 哈希表 + 双向链表
leetcode·缓存·散列表
洲覆14 小时前
Redis 核心数据类型:从命令、结构到实战应用
服务器·数据库·redis·缓存
RoboWizard20 小时前
传输无界 金士顿双接口U盘上新抽电脑
运维·人工智能·缓存·电脑·金士顿
祈祷苍天赐我java之术1 天前
Redis 缓存三大坑:击穿、穿透、雪崩的解析与解决
redis·缓存·mybatis