​LeetCode解法汇总146. LRU 缓存

news2024/5/18 18:39:16

 目录链接:

力扣编程题-解法汇总_分享+记录-CSDN博客

GitHub同步刷题项目:

https://github.com/September26/java-algorithms

原题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


描述:

请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

示例:

输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

提示:

  • 1 <= capacity <= 3000
  • 0 <= key <= 10000
  • 0 <= value <= 105
  • 最多调用 2 * 105 次 get 和 put

解题思路:

* 解题思路:

* 这题最难的其实就是处理双向链表的关系。

* 构建两个方法updateHead和updateTail,分别代表节点变动后处理头部节点和尾部节点。

* 处理头部节点时,分为两种情况,当前节点如果已经是头部节点,则不需要处理。否则,把current的前后节点相连接,然后把current放到头节点。

* 处理尾部节点时,分为3种情况,如果map中只有一个,则当前节点就是尾节点;如果map长度为2,则之前的header就是尾节点;如果current是尾节点,则断开其与前面节点的关系,设置其前面的节点为尾节点。

代码:

class LRUCache
{
public:
    class Node
    {
    public:
        int key;
        int val;
        Node *next;
        Node *pre;
        Node(int mkey = 0, int mvalue = 0) : key(mkey), val(mvalue), next(nullptr), pre(nullptr){};
    };

    int maxSize = 0;
    unordered_map<int, Node *> valueMap;
    Node *header = nullptr;
    Node *tail = nullptr;

    LRUCache(int capacity)
    {
        maxSize = capacity;
    }

    int get(int key)
    {
        if (valueMap.find(key) == valueMap.end())
        {
            return -1;
        }
        Node *current = valueMap[key];
        updateTail(current);
        updateHead(current);
        return valueMap[key]->val;
    }

    void put(int key, int value)
    {
        if (valueMap.find(key) != valueMap.end())
        {
            Node *current = valueMap[key];
            current->val = value;
            updateTail(current);
            updateHead(current);
            return;
        }
        if (valueMap.size() == maxSize)
        {
            removeNode();
        }
        addNode(key, value);
    }

    void addNode(int key, int value)
    {
        Node *current = new Node(key, value);
        valueMap[key] = current;
        updateTail(current);
        updateHead(current);
    }

    /**
     * 把current设置为header
     */
    void updateHead(Node *current)
    {
        if (header == current)
        {
            return;
        }

        // 链表中删除当前节点
        if (current->pre != nullptr)
        {
            current->pre->next = current->next;
        }
        if (current->next != nullptr)
        {
            current->next->pre = current->pre;
        }
        // 加入头节点
        current->next = header;
        current->pre = nullptr;
        if (header != nullptr)
        {
            header->pre = current;
        }
        header = current;
    }

    void updateTail(Node *current)
    {
        // 如果长度为1时
        if (valueMap.size() == 1)
        {
            tail = current;
            return;
        }

        if (valueMap.size() == 2)
        {
            tail->pre = current;
            tail = header;
        }
        else if (current == tail)
        {
            if (tail->pre != nullptr)
            {
                tail->pre->next = nullptr;
            }
            if (valueMap.size() > 1)
            {
                tail = current->pre;
            }
        }
    }

    void removeNode()
    {
        valueMap.erase(tail->key);
        Node *tailPre = tail->pre;
        if (tailPre == nullptr)
        {
            return;
        }
        tailPre->next = nullptr;
        tail->pre = nullptr;
        tail = tailPre;
    }
};

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

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

相关文章

TS编译选项——TS文件编译后消除注释

在tsconfig.json文件中配置removeComments属性 {"compilerOptions": {// outDir 用于指定编译后文件所在目录"outDir": "./dist", // 将编译后文件放在dis目录下// 是否文件编译后移除注释"removeComments": true} } 左边是编写的t…

通过解读yolov5_gpu_optimization学习如何使用onnx_surgon

onnx实战一: 解析yolov5 gpu的onnx优化案例: 这是一个英伟达的仓库, 这个仓库的做法就是通过用gs对onnx进行修改减少算子然后最后使用TensorRT插件实现算子&#xff0c; 左边是优化过的, 右边是原版的。 通过这个案例理解原版的onnx的导出流程然后我们看英伟达是怎么拿gs来优化…

伦敦银如何选择最优的交易方法

经常有投资者会问&#xff0c;伦敦银投资中如何选择最好的方法呢&#xff1f;我们进行伦敦银投资&#xff0c;目的就是找到一个能够盈利的交易方法&#xff0c;它能够使我们大部分交易都是盈利&#xff0c;少部分交易亏损&#xff0c;但是可以将亏损控制在一定的范围之内&#…

Windows10关闭此电脑“桌面”“图片”“视频”“3D对象”“文档”等显示,只显示“设备与驱动器”

如何关闭下图"文件夹"等7个子文件夹&#xff0c;只显示“设备和驱动器”&#xff1f; 关闭步骤&#xff1a; 打开cmd,输入regedit打开注册表编辑器打开注册表编辑器后&#xff0c;定位到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\My…

会声会影和剪映哪个好,2023年全新功能对比详细解析

随着网络视频的蓬勃发展&#xff0c;越来越多的人开始涉足视频剪辑领域&#xff0c;毕竟技多不压身嘛。在众多剪辑软件中&#xff0c;剪映和会声会影是备受新手青睐的两种。那么&#xff0c;会声会影和剪映哪个好呢&#xff1f;在它们之间&#xff0c;哪一个更适合初学者呢接&a…

软件测试之Web安全测试详解

前言 随着互联网时代的蓬勃发展&#xff0c;基于Web环境下的应用系统、应用软件也得到了越来越广泛的使用。 目前&#xff0c;很多企业的业务发展都依赖于互联网&#xff0c;比如&#xff0c;网上银行、网络购物、网络游戏等。但&#xff0c;由于很多恶意攻击者想通过截获他人…

ASCII码-对照表

ASCII 1> ASCII 控制字符2> ASCII 显示字符3> 常用ASCII码3.1> 【CR】\r 回车符3.2> 【LF】\n 换行符3.3> 不同操作系统&#xff0c;文件中换行 1> ASCII 控制字符 2> ASCII 显示字符 3> 常用ASCII码 3.1> 【CR】‘\r’ 回车符 CR Carriage Re…

如何通过git指令加入管理者仓库并提交分支(Github Gitee)

文章目录 创建GitHub、Gitee账户安装git下载gitgit基础配置 管理者创建gitee仓库新建仓库配置公钥 管理者管理仓库开发者通过git指令提交git提交错误原因&#xff1a; 创建GitHub、Gitee账户 GitHub&#xff1a; https://github.com/ Gitee &#xff1a; https://gitee.com/ …

redis做缓存(cache)

什么是缓存 缓存(Cache)的核心思路就是把一些常用的数据放到访问速度更快的地方&#xff0c;方便获取。关于硬件的访问速度来说 CPU寄存器>内存>硬盘>网络 因此常见使用内存作为硬盘的缓存&#xff0c;例如redis。使用硬盘作为网络的缓存&#xff0c;例如浏览器通过h…

2023-9-25 货仓选址

题目链接&#xff1a;货仓选址 #include <iostream> #include <algorithm>using namespace std;const int N 100010;int n; int a[N];int main() {cin >> n;for(int i 0; i < n; i ) cin >> a[i];sort(a, a n);int res 0;for(int i 0; i < …

生产管理看板系统助力高压线束生产车间实现生产任务的可视化管理

随着企业对生产智能化的追求不断提升&#xff0c;生产现场设备联网进行数据采集成为实现生产智能化的第一步&#xff0c;也是打造并实现数字化工厂最基础的一步。在这个过程中&#xff0c;生产管理看板系统发挥着重要的作用&#xff0c;能够实时在线统计车间工业生产设备的运行…

删除链表的倒数第N个节点-双指针法

【题目描述】 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 【示例】 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 输入&#xff1a;head [1,2], n …

CHAPTER 11: DESIGN A NEWS FEED SYSTEM

Step 1 - Understand the problem and establish design scope Candidate: Is this a mobile app? Or a web app? Or both? Interviewer: Both Candidate: What are the important features? Interview: A user can publish a post and see her friends’ posts on the ne…

《红警3》因计算机中丢失d3dx9_35.dll无法打开游戏怎么办?最新解决方法推荐

d3dx9_35.dll 是 DirectX 9.0c 的一部分&#xff0c;它是一个动态链接库 (DLL)&#xff0c;包含了许多用于支持 DirectX 9.0c 功能的函数和类。DirectX 是一种由微软开发的游戏和多媒体应用程序编程接口&#xff0c;它提供了许多功能&#xff0c;如 3D 图形、音频、输入等&…

电子器件系列55:lm339比较器

以这个比较器为例 电压比较器可以看作是放大倍数接近“无穷大”的运算放大器。 电压比较器的功能&#xff1a;比较两个电压的大小(用输出电压的高或低电平&#xff0c;表示两个输入电压的大小关系)&#xff1a; 当””输入端电压高于”&#xff0d;”输入端时&#xff0c;电压…

阿里巴巴中国站获得1688商品详情 API 返回值说明

1688商品详情API接口可以获得1688商品详情原数据。 这个API接口有两种参数&#xff0c;公共参数和请求参数。 公共参数有以下几个&#xff1a; apikey&#xff1a;这是您自己的API密钥&#xff0c;可以在1688开发者中心获取。 请求参数有以下几个&#xff1a; num_iid&…

115V/400Hz 中频交流航空电源系统测试负载箱

中频交流航空电源系统测试负载箱主要面向战斗机、教练机以及民航飞机的生产及使用单位&#xff0c;用于对航空电源系统&#xff08;28V低压直流电源系统、270V/540V高压电源系统和115V/230V三相400HZ交流电源系统&#xff09;进行维护测试、功能性验证、可靠性负载试验。 系统加…

uni-app:实现图片周围的图片按照圆进行展示

效果 代码 <template><view class"position"><view class"circle"><img src"/static/item1.png" class"center-image"><view v-for"(item, index) in itemList" :key"index" class&q…

通俗讲解MobileNet-v1/v2/v3网络

MobileNet网络是由google团队在2017年提出的&#xff0c;专注于移动端或者嵌入式设备中的轻量级CNN网络。相比传统卷积神经网络&#xff0c;在准确率小幅降低的前提下大大减少模型参数与运算量。(相比VGG16准确率减少了0.9%&#xff0c;但模型参数只有VGG的1/32)。MobileNet网络…

智慧电力平台打造无人值守配电房、变电所

随着科技的发展&#xff0c;电力行业也在不断进步。为了提高电力供应的可靠性和效率&#xff0c;智慧电力平台应运而生。通过智慧电力平台&#xff0c;打造无人值守配电房和变电所成为行业趋势。 一、无人值守配电房和变电所的概念 无人值守配电房和变电所是指通过数字化、…