146. LRU 缓存【 力扣(LeetCode) 】
零、原题链接
146. 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 ,则应该 逐出 最久未使用的关键字。
函数 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
三、解题思路
- 基本思路:
- 考虑 LRU 的本质,我们需要的是一个按访问时间排序的键值序列,这个序列的 CRUD 都要在 O ( 1 ) \Omicron(1) O(1) 的时间复杂度完成;
- C(增加):要在 O ( 1 ) \Omicron(1) O(1) 的时间复杂度内完成 且 保持序列有序,一般也只能考虑在序列尾部或者头部进行插入,在其他位置是不可能保证 O ( 1 ) \Omicron(1) O(1) 的时间复杂度的 且 序列有序的;考虑可以使用的数据结构:队列,栈;但是栈无法实现有序。
- R(查找):查找能在 O ( 1 ) \Omicron(1) O(1) 的时间复杂度完成,只能是 unordered_map ,如果只使用 unordered_map 是无法实现有序的,所以还需要其他结构来维护序列的按访问时间排序的特性,根据 C(增加) 分析的,使用队列;
- U(更新):首先 unordered_map 可以实现 O ( 1 ) \Omicron(1) O(1) 的更新操作,队列是没有办法实现 O ( 1 ) \Omicron(1) O(1) 的更新的,要实现,必须借助 unordered_map ,所以 unordered_map 必然要存放指向队列元素的指针;
- D(删除):unordered_map 可以在 O ( 1 ) \Omicron(1) O(1) 时间复杂度内删除,而队列要在 O ( 1 ) \Omicron(1) O(1) 时间复杂度内删除,考虑两种情况:
- 队列用数组实现:那只能把最后一个元素填充到要删除的元素的位置,然后删除末尾元素。但是只要就改变了序列的有序性,所以不能选用;
- 队列用链表实现:删除就是把对应结点删除,不会改变原来的有序性,且 unordered_map 中可以直接找到对应元素;考虑到链表删除需要待删除元素的前一个结点,所以链表要使用双链表;
- 确定数据结构为 unordered_map 和 双链表,unordered_map 用于实现 O ( 1 ) \Omicron(1) O(1) 复杂度的查找,双链表用于维持序列的有序性;双链表的头部存放最近最少使用的元素,尾部存放最近最多使用的元素,每次访问某个元素,就要把他移动到尾部,所以双链表还要可以在 O ( 1 ) \Omicron(1) O(1) 时间内访问到尾结点,可以考虑采用循环双链表;
- 考虑 LRU 的本质,我们需要的是一个按访问时间排序的键值序列,这个序列的 CRUD 都要在 O ( 1 ) \Omicron(1) O(1) 的时间复杂度完成;
- 具体思路:
- 数据结构采用 unordered_map 和 循环双链表;
- 编写更新结点函数 updateNode(M_ListNode* now),实现将结点移动到链表尾部;
- 对于尾结点,就不用移动了;
- 对于其他节点,先把该节点拆出来,然后拼接到链表尾部,也就是头结点的上一个结点;
- 对于构造函数 LRUCache(int capacity) ,存储容量和初始化空的循环双链表即可,创建一个头结点,不存放数据;
- 对于 get(int key) 函数,用 unordered_map 判断是否存在:
- 不存在返回 -1 ;
- 存在,则更新结点,调用 updateNode() 函数,然后返回对应的值;
- 对于 put(int key, int value) 函数,首先判断是新增还是更新:
- 新增:先判断容量是否满足:
- 不满足:修改循环双链表的头结点的下一个元素为新增元素,因为他是最近最少使用的;
- 满足:新增该元素;
- 然后然后调用 updateNode 更新该结点的次序;
- 更新:修改值,然后调用 updateNode 更新该结点的次序;
- 新增:先判断容量是否满足:
四、参考代码
时间复杂度: O ( 1 ) \Omicron(1) O(1)
空间复杂度: O ( n ) \Omicron(n) O(n)
typedef struct M_ListNode {int key = 0;int val;M_ListNode *pre, *next;M_ListNode() : val(0), pre(nullptr), next(nullptr) {}M_ListNode(int x) : val(x), pre(nullptr), next(nullptr) {}M_ListNode(int x, M_ListNode* next) : val(x), pre(nullptr), next(next) {}M_ListNode(int x, int y, M_ListNode* pre, M_ListNode* next): key(x), val(y), pre(pre), next(next) {}
} M_ListNode;class LRUCache {
public:M_ListNode* head = new M_ListNode(); // 循环双链表unordered_map<int, M_ListNode*> key_ptr; // key 和 存储 val 结点的指针int capacity;LRUCache(int capacity) {this->capacity = capacity;head->pre = head;head->next = head;}void updateNode(M_ListNode* now) { // 将结点移动到链表尾部if (now->next == head) // 尾结点不用移动return;now->pre->next = now->next;now->next->pre = now->pre;now->pre = head->pre;now->next = head;head->pre->next = now;head->pre = now;}int get(int key) {if (key_ptr.count(key) == 0)return -1;else {updateNode(key_ptr[key]);return key_ptr[key]->val;}}void put(int key, int value) {if (key_ptr.count(key) == 0) { // 新增if (key_ptr.size() == capacity) { // 满了,替换旧的key_ptr.erase(head->next->key);head->next->key = key;head->next->val = value;} else { // 插入新的M_ListNode* t = new M_ListNode(key, value, head, head->next); // 头插法head->next->pre = t;head->next = t;}key_ptr[key] = head->next;updateNode(head->next);} else { // 更新key_ptr[key]->val = value;updateNode(key_ptr[key]);}}
};/*** 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);*/
相关文章:
146. LRU 缓存【 力扣(LeetCode) 】
零、原题链接 146. LRU 缓存 一、题目描述 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中ÿ…...
【算法】链表:92.反转链表(medium)+双指针
系列专栏 《分治》 《模拟》 《Linux》 目录 1、题目链接 2、题目介绍 3、解法 (双指针) 4、代码 是 206. 反转链表 - 力扣(LeetCode)的类型题,且难度提升,可以先完成206,然后参照206的…...
Command | Ubuntu 个别实用命令记录(新建用户、查看网速等)
1. 实用命令 1.1 系统相关 1.1.1 查看系统、用户信息等 查看当前系统硬件架构 uname -m注:mac 上也能用 查看当前系统的操作系统及版本 cat /etc/os-release | grep "PRETTY_NAME"查看当前系统单个cpu的可用核心数 cat /proc/cpuinfo | grep "…...
云服务器部署k8s需要什么配置?
云服务器部署k8s需要什么配置?云服务器部署K8s需要至少2核CPU、4GB内存、50GBSSD存储的主节点用于管理集群,工作节点建议至少2核CPU、2GB内存、20GBSSD。还需安装Docker,选择兼容的Kubernetes版本,配置网络插件,以及确…...
Linux --入门学习笔记
文章目录 Linux概述基础篇Linux 的安装教程 ⇒ 太简单了,百度一搜一大堆。此处略……Linux 的目录结构常用的连接 linux 的开源软件vi 和 vim 编辑器Linux 的关机、开机、重启用户登录和注销用户管理添加用户 ⇒ ( useradd 用户名 ) ( useradd -d 制定目…...
并发编程三大特性(原子性、可见性、有序性)
并发编程的三大特性实际是JVM规范要求的JVM实现必须保证的三大特性 不同的硬件和不同的操作系统在内存管理上有一定的差异,JAVA为了解决这种差异,使用JMM(Java Memry Model)来屏蔽各个操作系统之间的差异,使得java可以…...
物理学基础精解【41】
文章目录 核物理基础 Υ \varUpsilon Υ衰变1. Υ \varUpsilon Υ衰变的一般性质2. 具体的衰变模式3. 衰变公式和机制4. 实验观测和理论研究 Υ \varUpsilon Υ衰变概述一、定义二、公式三、定理一、定义二、公式三、定理 重带电粒子概述重带电粒子的性质重带电粒子的公式 重带…...
深入理解Linux内核网络(一):内核接收数据包的过程
在应用层执行read调用后就能很方便地接收到来自网络的另一端发送过来的数据,其实在这一行代码下隐藏着非常多的内核组件细节工作。在本节中,将详细讲解数据包如何从内核到应用层,以intel igb网卡为例。 部分内容来源于 《深入理解Linux网络》…...
mysql学习教程,从入门到精通,SQL LIKE 运算符(28)
1、SQL LIKE 运算符 在SQL中,LIKE运算符主要用于在WHERE子句中搜索列中的指定模式。它通常与通配符一起使用,如%(代表零个、一个或多个字符)和_(代表单个字符),以执行模糊匹配。下面是一个使用…...
uniapp微信小程序使用ucharts遮挡自定义tabbar的最佳解决方案
如图所示: 使用的ucharts遮挡住了我自定义的tabbar(如果不是提需求的有病,我才不会去自定义tabbar) 查阅了不少文档,说是开启 ucharts 的 canvas2d 即可: 官网文档地址: uCharts官网 - 秋云…...
C初阶(八)选择结构(分支结构)--if、else、switch
前言: C语言是用来解决问题的,除了必要的数据输入与输出(见前文),还要有逻辑结构。其中基本可以归为三类:顺序结构、选择结构、循环结构。今天,杰哥提笔写的是关于选择结构(又叫“分…...
基于Springboot vue应急物资供应管理系统设计与实现
博主介绍:专注于Java(springboot ssm 等开发框架) vue .net php python(flask Django) 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设,从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找…...
区块链+Web3学习笔记
学习资料来源于B站: 17小时最全Web3教程:ERC20,NFT,Hardhat,CCIP跨链_哔哩哔哩_bilibili 该课程提供的Github代码地址,相关资料详见README.md: Web3_tutorial_Chinese/README.md at main sm…...
Redis: 集群高可用之节点与插槽管理
概述 Redis Cluster 集群模式,它使用的是分片来存储数据的,数据都存在多个节点上。而且使用了哈希槽这样的机制,它内部维护了 16384 个插槽那就是说每一个节点其实都具体的分布了一些槽,如果我们添加一个节点的话,槽总…...
HUAWEI New4.9G 与 2.6G 无法正常切换问题处理案例
HUAWEI New4.9G 与 2.6G 无法正常切换问题处理案例 在某地市的 XX 音乐节保障准备期间,为确保活动期间的网络质量,现场新开了 4.9G HUAWEI 室外基站。在网络优化和测试中,发现UE无法实现从 2.6G 到 4.9G 的正常切换。虽然现场具备 4.9G信号覆…...
Qt C++设计模式->责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象有机会处理请求,而不需要明确指定哪个对象处理。通过将这些对象连成一条链,请求沿着链传递,直到有对象处理它为止。该模式…...
paypal支付v2.0(php)支付代码
第一步:获取access_token: <?php$clientId ; // 替换为你的 PayPal Client ID $clientSecret ; // 替换为你的 PayPal Client Secret// PayPal API 请求的 URL $url "https://api-m.sandbox.paypal.com/v1/oauth2/token";// 初始化 cURL $ch …...
基于Python的自然语言处理系列(23):DrQA
在本篇文章中,我们将实现 DrQA 模型,该模型最初由论文 Reading Wikipedia to Answer Open-Domain Questions 提出。DrQA 是一种用于开放域问答系统的端到端解决方案,最初包括信息检索模块和深度学习模型。本次实现中,我们主要探讨 DrQA 的深度学习模型部分。 1. 数据加载 …...
誉天Linux云计算课程学什么?为什么保障就业?
一个IT工程师相当于干了哪些职业? 其中置顶回答生动而形象地描绘道: 一个IT工程师宛如一个超级多面手,相当于——加班狂程序员测试工程师实施工程师网络工程师电工装卸工搬运工超人。 此中酸甜苦辣咸,相信很多小伙伴们都深有体会。除了典…...
无人机控制和飞行、路径规划技术分析
无人机控制和飞行、路径规划技术是现代无人机技术的核心组成部分,它们共同决定了无人机的性能和应用范围。以下是对这些技术的详细分析: 一、无人机控制技术 无人机控制技术主要涉及飞行控制系统的设计、传感器数据的处理以及指令的发送与执行。飞行控…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
实战设计模式之模板方法模式
概述 模板方法模式定义了一个操作中的算法骨架,并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。简单来说,就是在一个方法中定义了要执行的步骤顺序或算法框架,但允许子类…...
ui框架-文件列表展示
ui框架-文件列表展示 介绍 UI框架的文件列表展示组件,可以展示文件夹,支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项,适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...
