当前位置: 首页 > news >正文

【链表】-Lc146-实现LRU(双向循环链表)

写在前面

  最近想复习一下数据结构与算法相关的内容,找一些题来做一做。如有更好思路,欢迎指正。


目录

  • 写在前面
  • 一、场景描述
  • 二、具体步骤
    • 1.环境说明
    • 2.双向循环链表
    • 3.代码
  • 写在后面


一、场景描述

  运用你所掌握的数据结构,设计和实现一个 LRU (Least Recently Used, 最近最少使用) 缓存机制。

它应该支持以下操作,获取数据 get 和 写入数据 put 。
1、获取数据 get(key), 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
2、写入数据 put(key, value), 如果密钥不存在,则写入其数据值,
当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?示例:
LRUCache cache = new LRUCache(2);// 缓存容量cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 该操作会使得密钥 2 作废
cache.get(2);       // 返回 -1 (未找到)
cache.put(4, 4);    // 该操作会使得密钥 1 作废
cache.get(1);       // 返回 -1 (未找到)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4

二、具体步骤

1.环境说明

名称说明
IntelliJ IDEA2019.2

2.双向循环链表

以下简单画了个图,说下双向循环链表的基本结构。

在这里插入图片描述

3.代码

以下为Java版本实现:

/*** LRU* 双向循环链表实现** @author qiuxianbao* @date 2024/02/14* @since ace_1.4.0_20240109*/
public class Lc146_LRU {public static void main(String[] args) {LRUCache cache = new LRUCache(2);cache.put(1, 1);System.out.println(cache);  // LRUCache{capacity=2, cacheMap.size=1, cacheMap={1=ListNode{key=1, value=1}}, dummy=ListNode{key=null, value=null}}cache.put(2, 2);System.out.println(cache);  // LRUCache{capacity=2, cacheMap.size=2, cacheMap={1=ListNode{key=1, value=1}, 2=ListNode{key=2, value=2}}, dummy=ListNode{key=null, value=null}}System.out.println(cache.get(1));  // 返回 1cache.put(3, 3);    // 该操作会使得密钥 2 作废System.out.println(cache);  // LRUCache{capacity=2, cacheMap.size=2, cacheMap={1=ListNode{key=1, value=1}, 3=ListNode{key=3, value=3}}, dummy=ListNode{key=null, value=null}}System.out.println(cache.get(2)); // 返回 -1 (未找到)cache.put(4, 4);    // 该操作会使得密钥 1 作废System.out.println(cache);  // LRUCache{capacity=2, cacheMap.size=2, cacheMap={3=ListNode{key=3, value=3}, 4=ListNode{key=4, value=4}}, dummy=ListNode{key=null, value=null}}System.out.println(cache.get(1)); // 返回 -1 (未找到)System.out.println(cache.get(3)); // 返回  3System.out.println(cache.get(4)); // 返回  4}/*** 思路:* 有 key 有 value,那么这个结点的 data有 int key, int value* 同时要具备很容易找到 头部(每次添加或获取时需要移动的) 和 尾部(删除) 节点* 因此,选择双向循环链表** 为了减少查找,可以借助于Map当做缓存(快速获取元素),用于表示实际容器大小* 还需要有一个LRU的大小 capacity,用于和实际容器大小 cacheMap.size 比较** put操作*      key存在,则更新 value,放到头部*      否则,判断是否超过容量*            超过,先删除链表尾部元素,然后再新增,放到头部*            否则,新增,放到头部* get操作*      每次都更新当结点到链表头部** 不管是put,还是get,都保证头部都是最新的节点** 定义 capacity,用于初始化存储容量* 定义一个 map 用于记录元素,方便判断是否存在以及根据 key去获取节点* 定义一个 双向循环链表,方便获取链表头部/尾部元素,便于添加/删除** 定义构造函数,用于初始化数据包括dummy节点*/static class LRUCache {// LRU大小int capacity;// 缓存,方便获取元素, size 就是元素实际的大小Map<Integer, ListNode> cacheMap;// 双向循环链表// dummy.next就是 head 节点,dummy.prev就是 tail 节点private ListNode dummy;public LRUCache(int capacity) {this.capacity = capacity;this.cacheMap = new HashMap<>();// 空元素初始化this.dummy = new ListNode();this.dummy.prev = this.dummy;this.dummy.next = this.dummy;}/*** 放元素* 也移动到头部,空间不足时,从尾部删除(需要有一个删除操作)** @param k* @param val*/public void put(int k, int val) {ListNode existNode = cacheMap.get(k);if (existNode != null) {existNode.value = val;move2Head(existNode);} else {if (cacheMap.size() >= this.capacity) {// 删除尾部结点ListNode tail = dummy.prev;delete(tail);// 删除缓存cacheMap.remove(tail.key);}// 构建新节点,添加到头部ListNode listNode = new ListNode(k, val);add2Head(listNode);cacheMap.put(k, listNode);}}/*** 获取元素* 时时移动到头部** @param k* @return*/public int get(int k) {int result = -1;ListNode listNode = cacheMap.get(k);if (listNode != null) {result = listNode.value;move2Head(listNode);}return result;}/*** 移动到头部* 先删除,再添加** @param e*/private void move2Head(ListNode e) {delete(e);add2Head(e);}/*** 添加到头部** @param e*/private void add2Head(ListNode e) {ListNode head = dummy.next;e.next = head;head.prev = e;e.prev = dummy;dummy.next = e;}/*** 删除节点** @param e*/private void delete(ListNode e) {ListNode p = e.prev;ListNode n = e.next;p.next = n;n.prev = p;e.prev = null;e.next = null;}@Overridepublic String toString() {return "LRUCache{" +"capacity=" + capacity +", cacheMap.size=" + cacheMap.size() +", cacheMap=" + cacheMap +", dummy=" + dummy +'}';}/*** 双向循环链表结构*/class ListNode {// 数据Integer key;Integer value;// 前驱指针ListNode prev;// 后继指针ListNode next;public ListNode() {}public ListNode(Integer key, Integer value) {this.key = key;this.value = value;}@Overridepublic String toString() {return "ListNode{" +"key=" + key +", value=" + value +'}';}}}}

写在后面

  如果本文内容对您有价值或者有启发的话,欢迎点赞、关注、评论和转发。您的反馈和陪伴将促进我们共同进步和成长。

相关文章:

【链表】-Lc146-实现LRU(双向循环链表)

写在前面 最近想复习一下数据结构与算法相关的内容&#xff0c;找一些题来做一做。如有更好思路&#xff0c;欢迎指正。 目录 写在前面一、场景描述二、具体步骤1.环境说明2.双向循环链表3.代码 写在后面 一、场景描述 运用你所掌握的数据结构&#xff0c;设计和实现一个 LRU (…...

MYSQL学习笔记:MYSQL存储引擎

MYSQL学习笔记&#xff1a;MYSQL存储引擎 MYSQL是插件式的存储引擎 存储引擎影响数据的存储方式 存储引擎是用来干什么的&#xff0c;innodb和myisam的主要区别–数据存储方式----索引 mysql> show engines; ----------------------------------------------------------…...

Bitcoin Bridge:治愈还是诅咒?

1. 引言 主要参考&#xff1a; Bitcoin Bridges: Cure or Curse? 2. 为何需关注Bitcoin bridge&#xff1f; 当前的Bitcoin bridge&#xff0c;其所谓bridge&#xff0c;实际是deposit&#xff1a; 在其它链上的BTC情况为&#xff1a; 尽管当前约有43.7万枚BTC在其它链上…...

Netty应用(七) 之 Handler Netty服务端编程总结

目录 15.Handler 15.1 handler的分类 15.1.1 按照方向划分 15.1.2 handler的结构 15.2 输入方向ChannelInboundHandlerAdapter 15.2.1 输出方向Handler的顺序 15.2.2 多个输入方向Handler之间的数据传递 15.2.2.1 handler消失了 15.2.2.2 手动编写netty提供的new Strin…...

LeetCode、1268. 搜索推荐系统【中等,前缀树+优先队列、排序+前缀匹配】

文章目录 前言LeetCode、1268. 搜索推荐系统【中等&#xff0c;前缀树优先队列、排序前缀匹配】题目类型及分类思路API调用&#xff08;排序前缀匹配&#xff09;前缀树优先队列 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创…...

计算机视觉基础:矩阵运算

矩阵及其表示方式 一个矩阵是由行(row)和列(column)组成的一个矩形数组&#xff0c;通常包含数字。我们可以用大写字母&#xff08;如 A、B&#xff09;来表示一个矩阵。例如&#xff0c;矩阵 A 可能看起来像这样&#xff1a; A [ a11 a12 a13 ][ a21 a22 a23 ][ a31 a32 a3…...

Gateway中Spring Security6统一处理CORS

文章目录 一、起因二、解决方法 一、起因 使用了gateway微服务作为整体的网关&#xff0c;并且整合了Spring Security6&#xff1b;还有一个system微服务&#xff0c;作为被请求的资源&#xff0c;当浏览器向gateway发送请求&#xff0c;请求system资源时&#xff0c;遇到CORS…...

突破编程_C++_基础教程(输入、输出与文件)

1 流和缓冲区 C中&#xff0c;流&#xff08; stream &#xff09;和缓冲区&#xff08; buffer &#xff09;是两个紧密相关的概念&#xff0c;它们在处理输入和输出时起着重要的作用。 流&#xff08; Stream &#xff09; 流是一种抽象的概念&#xff0c;用于表示数据的流动…...

UE的 HUD 类中的必备方法和属性

在屏幕上绘制的方法 1. DrawText() DrawText() 方法允许开发者在屏幕上渲染文本。参数包括文本内容、位置、颜色、字体、缩放等。 void DrawText(const FString& Text, const FLinearColor& TextColor, float ScreenX, float ScreenY, UFont* Font, float Scale 1.…...

单片机的认识

单片机的定义 先简单理解为&#xff1a; 在一片集成电路芯片上集成了微处理器&#xff08;CPU &#xff09;存储器&#xff08;ROM和RAM&#xff09;、I/O 接口电路&#xff0c;构成单芯片微型计算机&#xff0c;即为单片机。 把组成微型计算机的控制器、运算器、存储器、输…...

转发:udig安装 用来为geoserver上shp地图配置显示样式 颜色

下载udig&#xff0c;解压缩 这东东是基于eclipse的&#xff0c;需要Java JRE 把 JDK 1.8 里面的jre目录拷贝到 udig目录下面 udig下载、安装及汉化&#xff0c;简单生成geoserver图层样式sld-CSDN博客...

Linux--常用命令(详解)

详细目录 一、终端命令格式二、显示文件列表命令-ls2.1作用2.2格式2.3 ls常用选项2.3.1 ls -a2.3.2 ls -l(等价于 ll)2.3.2 ls -h 三、相对路径与绝对路径3.1绝对路径3.2相对路径 四、目录操作命令 -cd4.1作用4.2格式4.3案例4.3.1 cd -&#xff1a; 返回上一次所在目录4.3.2 cd…...

SouthLeetCode-打卡24年02月第1周

SouthLeetCode-打卡24年02月第1周 // Date : 2024/02/01 ~ 2024/02/04 034.合并两个有序链表 (1) 题目描述 034#LeetCode.21.#北岸计划2024/02/01 将两个升序链表合并为一个新的 升序 链表并返回。 新链表是通过拼接给定的两个链表的所有节点组成的。 (2) 题解代码 cla…...

vscode的cmake工具小三角符号旁边没有目标的解决方法

vscode里面写了个项目&#xff0c;找了半天没办法用cmake调试&#xff0c;最后发现是cmake里面的set(CMAKE_BUILD_TYPE Release)导致的&#xff0c;都是release模式了当然不能调试了&#xff1b;改成Debug就行了 参考&#xff1a;https://stackoverflow.com/questions/7549672…...

Servlet JSP-Eclipse安装配置Maven插件

Maven 是一款比较常用的 Java 开发拓展包&#xff0c;它相当于一个全自动 jar 包管理器&#xff0c;会导入用户开发时需要使用的相应 jar 包。使用 Maven 开发 Java 程序&#xff0c;可以极大提升开发者的开发效率。下面我就跟大家介绍一下如何在 Eclipse 里安装和配置 Maven 插…...

os模块

os 模块是 Python 中用于与操作系统进行交互的标准库之一。它提供了许多函数来执行文件和目录操作&#xff0c;管理进程以及与操作系统交互的其他功能。 下面是一些 os 模块中常用的函数和功能&#xff1a; 文件和目录操作&#xff1a; os.getcwd(): 返回当前工作目录的路径。…...

【C语言进阶】深度剖析数据在内存中的存储--上

1. C语言中的数据类型的简单介绍 注&#xff1a;C99标准里面&#xff0c;定义了bool类型变量。这时&#xff0c;只要引入头文件stdbool.h &#xff0c;就能在C语言里面正常使用bool类型。 1.1 在C语言中各类型所占内存空间的大小如下 char类型的数据类型大小为1字节即8比特位。…...

【doghead】VS2022 win11 安装配置WSL2 以编译linux端的cmake项目并运行2

【bifrost】VS2022 win11 安装配置WSL2 以编译linux端的cmake项目并运行1 完成了WSL2的安装。13900K 的电脑安装了ubuntu22.04构建中出现了一些问题,fix了。发现libuv 似乎不识别,认为是libuv.so ,无法让worker识别到uv 从而没构建。干脆单独构建好了,官方的脚本如此:而且…...

【教程】C++语言基础学习笔记(七)——Array数组

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【C语言基础学习】系列文章 第一章 《项目与程序结构》 第二章 《数据类型》 第三章 《运算符》 第四章 《流程控制》 第五章…...

BUGKU-WEB GET

题目描述 没有提示&#xff0c;就一个get&#xff0c;启动场景看看&#xff1a; 解题思路 显然是PHP语言解读分析代码吧写出你的payload 相关工具 略 解题步骤 进入场景分析代码 $what$_GET[what]; echo $what; if($whatflag) echo flag{****};前两句&#xff1a;使用get…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

rm视觉学习1-自瞄部分

首先先感谢中南大学的开源&#xff0c;提供了很全面的思路&#xff0c;减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接&#xff1a;https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架&#xff1a; 代码框架结构&#xff1a;readme有…...

FTXUI::Dom 模块

DOM 模块定义了分层的 FTXUI::Element 树&#xff0c;可用于构建复杂的终端界面&#xff0c;支持响应终端尺寸变化。 namespace ftxui {...// 定义文档 定义布局盒子 Element document vbox({// 设置文本 设置加粗 设置文本颜色text("The window") | bold | color(…...

EEG-fNIRS联合成像在跨频率耦合研究中的创新应用

摘要 神经影像技术对医学科学产生了深远的影响&#xff0c;推动了许多神经系统疾病研究的进展并改善了其诊断方法。在此背景下&#xff0c;基于神经血管耦合现象的多模态神经影像方法&#xff0c;通过融合各自优势来提供有关大脑皮层神经活动的互补信息。在这里&#xff0c;本研…...

STL 2迭代器

文章目录 1.迭代器2.输入迭代器3.输出迭代器1.插入迭代器 4.前向迭代器5.双向迭代器6.随机访问迭代器7.不同容器返回的迭代器类型1.输入 / 输出迭代器2.前向迭代器3.双向迭代器4.随机访问迭代器5.特殊迭代器适配器6.为什么 unordered_set 只提供前向迭代器&#xff1f; 1.迭代器…...