35 LRU缓存

news2024/11/24 0:30:56

LRU缓存

    • 题解1 双map(差2个testcases)
    • 题解2 哈希表+双向链表(参考)
    • 题解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 2105getput

题解1 双map(差2个testcases)

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 哈希表+双向链表(参考)

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

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]);
        }
    }
};

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1050194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通讯网关软件016——利用CommGate X2Access实现OPC数据转储Access

本文介绍利用CommGate X2ACCESS实现从OPC Server读取数据并转储至ACCESS数据库。CommGate X2ACCESS是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现从OPC Server读取数据并转储至ACCESS…

【前段基础入门之】=>CSS 常用的字体文本属性

导读&#xff1a; 这一章&#xff0c;主要分享一些 CSS 中的一些&#xff0c;常用的 字体和文本方面的属性。 文章目录 字体属性字体大小字体族字体风格字体粗细字体复合写法 文本属性文本间距文本修饰文本缩进文本水平对齐行高vertical-align 字体属性 字体大小 属性名&…

进入Linux的世界

了解Linux的历史 一、Linux发展史二、企业应用现状三、Linux操作系统的各种版本 一、Linux发展史 了解一下硅谷模式: 1945年——1991年是美苏冷战的时间&#xff0c;在这个环境背景下&#xff0c;计算机诞生了。 Linux的发展史&#xff1a; 查看Linux纯源代码 二、企业…

No144.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

完整的 pixel 6a 刷入 AOSP 源码过程记录

基础环境 虚拟机&#xff1a;VMware Workstation 16 Pro 16.0.0 build-16894299 Linux版本&#xff1a;ubuntu-16.04.7-desktop-amd64 设备&#xff1a;pixel 6a&#xff1b;代号&#xff1a;bluejay&#xff1b; 基础软件安装 安装 Git 命令&#xff1a;sudo apt install git …

ATA-M系列功率放大器——应用场景介绍

ATA-M系列是一款理想的单通道功率放大器。最大输出690Vrms电压&#xff0c;800VA功率&#xff0c;可驱动0~100%的阻性或非阻性负载。输出阻抗匹配多个档位可选&#xff0c;客户可根据测试需求调节。 图&#xff1a;ATA-M系列功率放大器 国产品牌安泰电子自主研发的ATA-M系列功率…

MySQL MMM高可用架构

MySQL MMM高可用架构一、MMM概述1、MMM简介2、MMM高可用架构3、MMM故障切换流程 二、MMM高可用双主双从架构部署1、配置主主复制&#xff08;master&#xff09;&#xff0c;主从复制&#xff08;slave&#xff09;1&#xff09;修改 Master1的MySQL配置文件2&#xff09;把配置…

Linux 压缩和解压

1、tar命令&#xff08;复杂&#xff09; 使用tar命令均可以进行压缩和解压缩的操作 语法&#xff1a;tar [-c -v -x -f -z -C] 参数1 参数2 ... 参数N -c&#xff0c;创建压缩文件&#xff0c;用于压缩模式 -v&#xff0c;显示压缩、解压过程&#xff0c;用于查看进度 -x&am…

redis查看耗时久的命令

redis查看耗时久的命令主要有两招&#xff1a;latency和slow log 【latency】 在Redis中&#xff0c;latency命令用于监视和测量Redis实例的延迟。 先进入redis: redis-cli -h 127.0.0.1 -p 24000[查看延迟监视器阈值] CONFIG GET latency-monitor-threshold这个值返回0&…

N9917A|是德科技keysight N9917A微波分析仪

181/2461/8938毫米波频率测量需要精确和谨慎。幸运的是&#xff0c;随着更多的毫米测试设备问世&#xff0c;工程挑战的难度略有下降。信号分析仪现已将同轴器件的直接覆盖范围扩大到110 GHz。这提供了低噪声、高精度和宽带宽的优势&#xff0c;使工程师能够专注于他们的设计和…

ESP32IDF出现Syntax Warning in cmake code at column 47报错

前言 &#xff08;1&#xff09;ESP32的资料还是挺难找的&#xff0c;遇到bug处理起来挺折磨人的。今天分享一个我遇到的bug&#xff0c;以及处理思路。 报错日志 &#xff08;1&#xff09;前天在些博客的时候&#xff0c;做测试发现了一个奇怪的bug&#xff0c;报错日志如下。…

Linux 本地 Docker Registry本地镜像仓库远程连接

目录 Linux 本地 Docker Registry本地镜像仓库远程连接 1. 部署Docker Registry 2. 本地测试推送镜像 3. Linux 安装cpolar 4. 配置Docker Registry公网访问地址 5. 公网远程推送Docker Registry 6. 固定Docker Registry公网地址 Linux 本地 Docker Registry本地镜像仓库…

Linux Kernel 之十 虚拟化、VirtIO 架构及规范、VirtQueue VRing

VirtIO 是一种 IO 半虚拟化解决方案&#xff0c;它提供 Guest OS 与 Hypervisor 虚拟化设备之间的通信框架和编程接口。其主要的优势是能提高性能且减少跨平台带来的兼容性问题。本文重点结合 VirtIO 规范 1.1 版以及 Linux 中的源码来分析 VirtIO 框架。 本文是我自己学习虚拟…

【Vue.js】使用Element入门搭建登入注册界面axios中GET请求与POST请求跨域问题

一&#xff0c;ElementUI是什么&#xff1f; Element UI 是一个基于 Vue.js 的桌面端组件库&#xff0c;它提供了一套丰富的 UI 组件&#xff0c;用于构建用户界面。Element UI 的目标是提供简洁、易用、美观的组件&#xff0c;同时保持灵活性和可定制性 二&#xff0c;Element…

idea2023根据表自动生成+springboot跑起来

idea安装插件 idea中显示数据库连接 就可以看到如下界面 选中你想生成的表&#xff0c;右键如下操作 如上就有了所有需要的后端代码 生成后&#xff0c;要查看一下mapper.xml中的文件是否 正确&#xff0c;若有误请先去修改&#xff0c;例如我的版本下生成了xml文件中缺乏…

Firecamp2.7.1exe安装与工具调试向后端发送SocketIO请求

背景&#xff1a; 笔者在python使用socket-io包时需要一个测试工具&#xff0c;选择了firecamp这个测试工具来发送请求。 参考视频与exe资源包&#xff1a; Firecamp2.7.1exe安装包以及基本使用说明文档&#xff08;以SocketIO为例&#xff09;.zip资源-CSDN文库 15_send方法…

如何注册一个 DA 为 10 的高价值老域名

众所周知&#xff0c;由于域名存在唯一性&#xff0c;随着人们注册的越多&#xff0c;好域名也变得越来越少&#xff0c;渐渐成为稀缺的网络资源。这个时候要想拥有好的域名&#xff0c;抢注优质老域名就成了广大米友的路径之一。 优质的高价值域名都有一个特点&#xff0c;那…

Tomcat多实例+Nginx动静分离、负载均衡

这里写目录标题 Tomcat多实例动静分离、负载均衡一、Tomcat多实例部署1、安装JDK2、安装启动tomcat 二、NginxTomcat负载均衡、动静分离1、Nginx负载均衡实现原理1.1 原理1.2 Nginx配置反向代理的主要参数 2、Nginx动静分离实现原理2.1 原理2.2 Nginx静态处理优势 3、动静分离配…

AIGC(生成式AI)试用 7 -- 桌面小程序

生成式AI&#xff0c;别人用来写作&#xff0c;我先用来写个桌面小程序。 桌面小程序&#xff1a;计算器 需求 Python开发图形界面&#xff0c;标题&#xff1a;计算器 - * / 基本运算计算范围&#xff1a;-999999999 ~ 999999999** 乘方计算&#xff08;例&#xff0c;2*…

第78步 时间序列建模实战:随机森林回归建模

基于WIN10的64位系统演示 一、写在前面 之前我们以决策树为例子&#xff0c;展示了各种花里胡哨的时间序列建模。 从这一期开始&#xff0c;我们继续基于python构建各种机器学习和深度学习的时间序列预测模型。 同样&#xff0c;这里使用这个数据&#xff1a; 《PLoS One》…