当前位置: 首页 > news >正文

力扣146 - LRU缓存

视频讲解

哈希 + 双向链表

为什么要用双向链表?

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

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

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

demo:

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);
 */

相关文章:

  • 恶劣天候三维目标检测论文列表整理
  • 海思Hi3516DV300交叉编译opencv
  • 【C#】详解C#中的内存管理机制
  • 如何在PHP中实现API版本管理:保持向后兼容性
  • 数据结构--顺序表
  • Elasticsearch 2025/3/7
  • 工程化与框架系列(22)--前端性能优化(中)
  • Android 仿 DeepSeek 思考效果:逐字显示 AI 生成内容,支持加粗、颜色,复制内容
  • DeepSeek-R1:引领AI领域革新,MLA技术助力模型迁移
  • 【从零开始学习计算机科学】数字逻辑(五) Verilog HDL语言
  • HTTP请求方法:POST与GET的深度解析
  • Linux驱动开发(1.基础创建)
  • Electron:点击右键保存图片到本地
  • mapbox进阶,模仿百度,简单实现室内楼层切换
  • Redis网络模型
  • 学习笔记:于博士SI揭秘实记第一章 概述
  • RabbitMQ 高级特性解析:RabbitMQ 消息可靠性保障 (上)
  • Visual Studio Code打开远程服务器项目,打开服务器Android上百G源码,SSH免密连接方式
  • 蓝桥杯备考:六级词汇积累(day5)
  • 闭包+求解候选码+最小函数依赖集
  • 郑州模板网站建设/培训机构招生方案
  • 义乌加工厂接单平台/网站外链的优化方法
  • 邢台专业网站建设公司推荐/哪个平台推广效果最好
  • 网站怎么换空间/打开百度浏览器
  • 自己做的网站会被黑吗/淘宝培训
  • 中国免费网站建设/申请网站域名要多少钱