leetcode_146 LRU缓存 - 详解

news/2025/10/23 18:01:28/文章来源:https://www.cnblogs.com/tlnshuju/p/19161293

leetcode_146 LRU缓存 - 详解

2025-10-23 17:59  tlnshuju  阅读(0)  评论(0)    收藏  举报

1. 题意

请你设计并实现一个满足 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) 的平均时间复杂度运行。

2. 题解

单次插入需要O(1)O(1)O(1)

查找也需要是O(1)O(1)O(1)

因此我们需要哈希表和双向链表来完成这一操作。

2.1 我的解

直接自己写个双向链表。

同时我们需要维护链表头和尾。

需要注意的是一些异常情况,比如链表空,或者只有一个头节点。

class LRUCache {
public:
struct LRUNode {
LRUNode(int k, int v):key(k),value(v) {
}
int key;
int value;
};
struct LRUList {
LRUList *pre;
LRUList *next;
LRUNode *node;
};
LRUCache(int capacity):max_cap_(capacity){
}
int get(int key) {
// cout << "get " << key << "\n";
if ( hs.count(key) ) {
LRUList *cur = hs[key];
if ( cur != head) {
if ( cur == tail)
tail = cur->pre;
cur->pre->next = cur->next;
if (cur->next)
cur->next->pre = cur->pre;
head->pre  = cur;
cur->next = head;
cur->pre  = NULL;
head = cur;
}
return cur->node->value;
}
return -1;
}
void put(int key, int value) {
// cout << "put: [ " << key <<", " << value << " ]" << "\n"; 
if ( hs.count(key) ) {
LRUList *cur = hs[key];
cur->node->value = value;
if (cur == head)
return;
if ( cur == tail) {
tail = cur->pre;
}
cur->pre->next = cur->next;
if (cur->next)
cur->next->pre = cur->pre;
head->pre  = cur;
cur->next = head;
cur->pre  = NULL;
head = cur;
}
else {
LRUList *cur = new LRUList;
cur->pre = cur->next = NULL;
cur->node = new LRUNode(key, value);
++cur_cap_;
hs[key] = cur;
if (head)
head->pre = cur;
if (tail == NULL)
tail = cur;
cur->next = head;
head = cur;
if ( cur_cap_ > max_cap_) {
LRUList *del = tail;
// cout << "del " << del->node->key << "\n";hs.erase(del->node->key);tail = del->pre;if (tail)tail->next = NULL;del->pre = NULL;del->next = NULL;delete del->node;delete del;--cur_cap_;}}}private:int max_cap_;int cur_cap_{};unordered_map<int,LRUList *> hs;LRUList *head{};LRUList *tail{};};/*** 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.2 0x3f的解

我看0x3f的解,主要是模块化,还有加了一个哨兵节点就省去了首尾节点的判断。

class LRUCache {
public:
struct LRUNode {
LRUNode():pre(NULL),next(NULL) {
}
LRUNode(int key, int val):k(key),v(val), pre(NULL), next(NULL){
}
int k;
int v;
LRUNode *pre;
LRUNode *next;
};
private:
int cap_;
unordered_map<int, LRUNode *> key_to_node;LRUNode *dumNode;public:LRUCache(int capacity) : cap_(capacity), dumNode(new LRUNode()) {dumNode->pre = dumNode;dumNode->next = dumNode;}void remove(LRUNode *cur) {cur->pre->next = cur->next;cur->next->pre = cur->pre;cur->pre = cur->next = NULL;}void push_front(LRUNode *cur) {cur->next = dumNode->next;cur->pre  = dumNode;dumNode->next->pre =cur;dumNode->next = cur;}int get(int key) {//cout << "get " << key << "\n";auto it = key_to_node.find(key);if ( it != key_to_node.end()) {LRUNode *cur = it->second;remove( cur );push_front( cur );return cur->v;}return -1;}void put(int key, int value) {//cout << "put [ " << key << ", " << value << " ]\n";auto it = key_to_node.find(key);if ( it != key_to_node.end()) {LRUNode *cur  = it->second;cur->v = value;remove( cur );push_front( cur );}else {LRUNode *cur = new LRUNode(key, value);key_to_node[key] = cur;push_front(cur);if ( key_to_node.size() > cap_) {LRUNode *del_node = dumNode->pre;key_to_node.erase( del_node->k);remove( del_node);delete del_node;}}}};

还有一种就是使用标准库的双向链表了,不过标准库的api真的感觉好难用!

class LRUCache {
public:
struct LRUNode {
LRUNode(int k, int v):key(k),value(v) {
}
int key;
int value;
};
struct LRUList {
LRUList *pre;
LRUList *next;
LRUNode *node;
};
LRUCache(int capacity):max_cap_(capacity){
}
int get(int key) {
// cout << "get " << key << "\n";
auto it = key_to_it.find(key);
if ( it  == key_to_it.end()) {
return -1;
}
cached_list.splice( cached_list.begin(), cached_list, it->second);
return cached_list.begin()->value;
}
void put(int key, int value) {
auto it = key_to_it.find( key );
if ( it != key_to_it.end()) {
it->second->value = value;
cached_list.splice( cached_list.begin(), cached_list, it->second);
}
else {
auto nNode = new LRUNode(key, value);
cached_list.push_front( *nNode );
key_to_it[key] = cached_list.begin();
if ( cached_list.size() > max_cap_) {
key_to_it.erase(cached_list.back().key );
cached_list.pop_back();
}
}
}
private:
int max_cap_;
unordered_map<int, list<LRUNode>::iterator> key_to_it;list<LRUNode> cached_list;};/*** 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);*/

3. 参考

0x3f

cpp-splice

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

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

相关文章

杜邦线 2头的

杜邦线 2头的🔹 三、常见几种组合线型两端类型典型用途公-母 一端公,一端母 最常见,用于开发板 ↔ 传感器模块公-公 两端都是针头 面包板 ↔ 面包板,或跳线连接母-母 两端都是插孔 两个模块或引脚连接

第一!天翼云引领中国教育公有云市场

近日,国际数据公司IDC发布的《中国教育云市场份额,2024:政策技术双驱增长,需求分层与竞争格局成型》(Doc# CHC53785125,2025年10月)报告显示,中国电信天翼云以16.38%的市场份额位居中国教育公有云市场第一,凭…

阿里云加持,《泡姆泡姆》让全球玩家畅享零延迟冒险

为保障全球玩家始终获得稳定、低延迟、无中断的联机体验,《泡姆泡姆》构建了一套以云原生为核心、自动化为驱动、可观测为基础的技术架构体系,实现了从基础设施到应用层的全栈可控,支撑全球化部署与持续迭代运营。关…

(二)从分层架构到数据湖仓架构:数据仓库分层下的技术架构与举例

本文为系列文章第二篇,详细剖析了数据仓库分层下的技术架构,并附以以示例,希望能够为相关从业者提供数据湖仓设计与实践的系统指引。《新兴数据湖仓设计与实践手册从分层架构到数据湖仓架构设计(2025 年)》 系列文…

2025 年压滤机厂家最新推荐排行榜:隔膜 / 污泥 / 真空 / 板框 / 带式压滤机优质品牌权威指南

在环保政策收紧与工业智能化升级的双重驱动下,压滤机作为固液分离核心设备,已成为化工、矿山、环保等领域的刚需装备。但当前市场呈现 “两极分化” 态势:头部品牌技术壁垒高但选型复杂,中小品牌价格混乱且质量无保…

2025 年氮化硅陶瓷球生产厂家最新推荐榜:高精度高耐磨产品优选,国内优质企业全面剖析

在高端制造业持续升级的当下,氮化硅陶瓷球因高精度、高硬度、高耐磨等优势,成为新能源汽车、精密机床、风力发电等领域的关键零部件。然而,当前市场上生产厂家数量繁杂,部分企业存在技术落后、原材料劣质等问题,导…

第一次大作业心得

View Post第一次大作业心得102300213 陈宇我们组的项目是“旅行助手”:通过 AI 整合能力,让用户仅通过一次交互,即可获取 “天气 + 攻略 + 景点推荐” 的一站式旅行规划信息,降低旅行规划的时间成本与操作复杂度。…

VScodeC语言结构体成员提示不全

VScodeC语言结构体成员提示不全,把#include "main.h"移到最上边写STM32代码,以 test.c 和 test.h 举例 test.c中test.c #include "main.h" // <----这个移到最上边就好了 #include "tes…

2025滑石粉厂家推荐辽宁精华新材料,纳米级/工业级/化妆品级多品类覆盖

2025滑石粉厂家推荐辽宁精华新材料,纳米级/工业级/化妆品级多品类覆盖 技术挑战与行业痛点 滑石粉作为一种重要的工业原料,在塑料、涂料、化妆品、食品等多个领域发挥着关键作用。然而,随着应用领域的不断扩展和要求…

2025真空烧结炉厂家推荐沈阳恒进,专业品质与高效服务双重保障

2025真空烧结炉厂家推荐沈阳恒进,专业品质与高效服务双重保障 在高端制造业快速发展的今天,真空烧结炉作为新材料研发和精密制造的关键设备,其技术水平和性能指标直接影响着产品质量和生产效率。随着2025年的临近,…

基于粒子群优化(PSO)算法的PID控制器参数整定

一、PSO-PID整定原理框架 graph TD A[初始化粒子群] --> B[计算适应度] B --> C{更新个体/全局最优} C -->|是| D[更新速度与位置] C -->|否| E[判断终止条件] D --> B E -->|满足条件| F[输出最优参…

详细介绍:python(73) 引用.dll文件并调用函数

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

承插焊异径三通源头厂家推荐上海结申,专业制造高压承插管件

在工业管道系统领域,承插焊异径三通作为关键连接部件,其质量直接关系到整个管道系统的安全性与效率。为提供客观的行业参考,本报告通过对业内主要生产企业的产能规模、技术研发实力、产品质量管控及市场应用数据等多…

【10.29 直播】IoTDB 图形化工具与编程框架集成实操

10.29 19 点,助你实现跨平台图形化操作,快速搭建系统模块!🔍你是否曾为时序数据库 IoTDB 的命令行操作而烦恼? 🚀是否希望像使用 MySQL 一样,通过熟悉的 GUI 工具轻松管理和查询时序数据? 📌到底如何将 Io…

锻造承插三通厂家专业技术对比,上海结申管件承压性能提升28%使用寿命延长35%

在石油化工、市政工程等工业领域,锻造承插三通作为管道系统的关键连接部件,其承载强度、密封性能及耐久性直接关系到整个系统的安全运行。随着工业基础设施升级,市场对高强度、高精度管件的需求持续增长。本报告基于…

2025棒球帽/卫衣/羽绒服品牌推荐,COVERNAT潮流服饰厂家精选

2025棒球帽/卫衣/羽绒服品牌推荐,COVERNAT潮流服饰厂家精选 当前棒球帽、卫衣、羽绒服领域的技术挑战 在时尚服饰行业快速发展的今天,棒球帽、卫衣和羽绒服作为日常穿搭的重要组成部分,面临着诸多技术挑战。根据行业…

如何在CentOS 7上安装bzip2-1.0.6-13.el7.x86_64.rpm RPM包(详细步骤) - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

上海结申管件制造有限公司:承插焊异径三通、承插焊Y型三通、高压承插管件、锻造承插三通源头厂家

在石油化工、市政工程等工业领域,承插焊Y型三通作为管道系统的关键连接部件,其密封性能、承压能力及使用寿命直接关系到整个系统的安全运行。据2025年行业调研数据显示,全球工业管件市场规模预计突破800亿美元,其中…

harbor基于自建证书部署HTTPS及k8s集群

harbor基于自建证书部署HTTPS及k8s集群docker和k8s的时间简史时间阶段关键事件萌芽与诞生(2013-2014) • 2013: Docker开源 (基于go语言编写)• 2014: Google公司开源Kubernetes,默认以Docker 为运行时• 生态分化: D…

python练习 石头剪刀布

目标 1.强化多条件的逻辑运算 2.体会import导入random模块的使用 需求 3.从控制台输入要出的拳--石头1、剪刀2、布3 4.电脑随机出拳 代码实现 import random while True: num=random.randint(1,3) compute=num me=int(…