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工程师宛如一个超级多面手,相当于——加班狂程序员测试工程师实施工程师网络工程师电工装卸工搬运工超人。 此中酸甜苦辣咸,相信很多小伙伴们都深有体会。除了典…...

无人机控制和飞行、路径规划技术分析
无人机控制和飞行、路径规划技术是现代无人机技术的核心组成部分,它们共同决定了无人机的性能和应用范围。以下是对这些技术的详细分析: 一、无人机控制技术 无人机控制技术主要涉及飞行控制系统的设计、传感器数据的处理以及指令的发送与执行。飞行控…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...