【算法】【线性表】【链表】LRU 缓存2

news/2024/11/19 4:30:50/文章来源:https://www.cnblogs.com/kukuxjx/p/18348227

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) 的平均时间复杂度运行。

示例:

输入
["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

2  解答

上次我写了一个,今儿再写一个比较清晰的,主要思路就是:get 的时候,如果存在的话,要把它移动到头部,put的时候如果 key 存在,更新value后要把它移动到头部,不存在的话,要看删不删旧的,并把新的添加到头部:

public class LRUCache {// 容量大小private int capacity;// 链表头节点 方便处理private LRUNode head;// 某个元素存在或者不存在 所以需要 map 进行判断private Map<Integer, LRUNode> map;public LRUCache(int capacity) {if (capacity <= 0) throw new IllegalArgumentException("容量不能小于0");this.capacity = capacity;this.head = new LRUNode(0, 0);this.map = new HashMap<>(capacity);this.head.preNode = this.head;this.head.nextNode = this.head;}// 链表节点class LRUNode {private int key;private int value;private LRUNode preNode;private LRUNode nextNode;public LRUNode(int key, int value) {this.key = key;this.value = value;}public LRUNode(int key, int value, LRUNode preNode) {this.key = key;this.value = value;this.preNode = preNode;}public LRUNode(int key, int value, LRUNode preNode, LRUNode nextNode) {this.key = key;this.value = value;this.preNode = preNode;this.nextNode = nextNode;}}public int get(int key) {// 不存在直接返回 -1LRUNode node = map.get(key);if (Objects.isNull(node)) {return -1;}// 就一个元素的话或者它本身就在第一个 不需要移动int res = node.value;if (map.size() <= 1) return res;if (node.preNode == this.head) return res;// 说明大于1个元素并且它还不在第一的位置,就需要把它移动到头部去// 为什么需要移动?因为put满的情况下要删除最不常用的 所以要移动保证删除的时候是O(1)LRUNode preNode = node.preNode;// 因为有头节点的存在 所以这个前置节点一定不为空LRUNode nextNode = node.nextNode;// 将当前要移动的节点 先释放出来nextNode.preNode = preNode;preNode.nextNode = nextNode;// 该节点的前后都重新指向node.preNode = this.head;node.nextNode = head.nextNode;// 插进来head.nextNode.preNode = node;head.nextNode = node;// 返回结果return res;}public void put(int key, int value) {LRUNode node = map.get(key);// 存在的话,直接更新if (Objects.nonNull(node)) {node.value = value;// 这里很重要 因为存在更新完value 要把这个节点释放出来,下边要对这个节点移动到头部LRUNode preNode = node.preNode;LRUNode nextNode = node.nextNode;nextNode.preNode = preNode;preNode.nextNode = nextNode;} else {// 没有的话 说明不存在需要把它插进来// 先判断满没满if (map.size() < this.capacity) {// 没满直接头插法把它带进来node = new LRUNode(key, value);this.map.put(key, node);} else {// 满了的话 需要移出尾部node = this.head.preNode;map.remove(node.key);node.key = key;node.value = value;map.put(key, node);LRUNode lastPreNode = node.preNode;lastPreNode.nextNode = this.head;this.head.preNode = lastPreNode;}}// node即为需要插入到头部的节点// 重新赋值 node 信息node.nextNode = this.head.nextNode;node.preNode = this.head;// 放到头部LRUNode headNextNode = this.head.nextNode;headNextNode.preNode = node;this.head.nextNode = node;}// 打印链表信息
    @Overridepublic String toString() {LRUNode node = this.head.nextNode;StringBuilder builder = new StringBuilder();while (node != this.head) {builder.append(node.key).append("(").append(node.value).append(")");node = node.nextNode;}return builder.toString();}
}

打败的人数有点少哇,哈哈哈,上次写的那个一会儿moveLast 一会儿 moveFirst 的不够精简,这次写的简单点,有理解不对的地方欢迎指正哈。

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

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

相关文章

介绍一款新奇的开源操作系统:GodoOS

在快节奏的现代办公环境中,一款高效、集成化的操作系统无疑是提升工作效率的利器。今天,我们要为您隆重介绍 ——GodoOS,一款专为内网办公环境设计的全能操作系统。它不仅仅是一个工具,更是您团队协作与文件管理的得力助手,将彻底改变您的工作方式,带来前所未有的便捷体验…

CORS跨域漏洞修复

原文链接: https://www.cnblogs.com/wenyoudo/p/14862701.html 漏洞介绍概述:CORS,跨域资源共享(Cross-origin resource sharing),是H5提供的一种机制,WEB应用程序可以通过在HTTP增加字段来告诉浏览器,哪些不同来源的服务器是有权访问本站资源的,当不同域的请求发生时,…

lg-dp1

记忆化搜索:记忆化压缩 DP 状态(一些期望 dp 里会用)剪枝递推:保证前面的部分已经计算了数位 dp 求 \([l,r]\) 之内满足某种限制的数的个数,该限制应该是与数位有关系的。 带不带前导0取决于是否对统计答案造成影响。 前缀和转化:只有上界补充题:如果 lim=1 的时候前面都…

《最新出炉》系列小成篇-Python+Playwright自动化测试-66 - 等待元素至指定状态(出现、移除、显示和隐藏)

1.简介 在我们日常工作中进行UI自动化测试时,保证测试的稳定性至关重要。其中一个关键方面是正确地定位和操作网页中的元素。在网页中,元素可能处于不同的状态,有些可能在页面加载完成之前不在DOM中,需要某些操作后才会出现,而其他元素可能一直存在于DOM中,但最初处于隐藏…

BACnet初学者教程,第三章:什么是 BACnet/IP 网络

第三章:什么是 BACnet/IP 网络平时调试BACnet协议,一个好用的 BACnet 调试工具和模拟器必不可少,推荐一款: 官网地址:https://www.redisant.cn/bacnetexplorerBACnet/IP 网络是一个或多个 IP 子网(IP 域)的集合,这些子网分配有单个 BACnet 网络号。BACnet 互联网络由两…

BACnet初学者教程,第四章:介绍 BACnet 虚拟链路层

第四章:介绍 BACnet 虚拟链路层平时调试BACnet协议,一个好用的 BACnet 调试工具和模拟器必不可少,推荐一款: 官网地址:https://www.redisant.cn/bacnetexplorer虚拟链路层 (VLL) 背后的基本概念是向现有的 BACnet 网络层呈现某些网络拓扑和功能的视图,利用新协议中内置的…

读零信任网络:在不可信网络中构建安全系统12源代码和构建系统

读零信任网络:在不可信网络中构建安全系统12源代码和构建系统1. 建立应用信任 1.1. 软件正在吞噬整个世界 1.2. 零信任网络需要关注应用程序的安全性,这似乎违反直觉,毕竟网络是不可信的,因此可以预见网络上存在不可信的应用 1.3. 运行在数据中心的软件堪称一切魔法之源,因…

雷达气象相关词汇(二 偏振参量)

参考自https://www.radartutorial.eu/15.weather/wr20.en.html 双偏振雷达 使用双偏振是区分冰雹和雨滴的一种方法。雷达发射和接收线性极化电磁波信号,并在水平和垂直偏振之间快速切换,在单个发射脉冲之间或在脉冲组之间交替。现代双偏振雷达通常同时传输两个偏振方向。示意…

第十章 自定义模块

10.1 导入模块 1.什么是python模块? ​ Python模块(Module),是一个Python文件,以.py结尾 模块可以定义函数,类和变量,模块里也能包含可执行的代码 2.模块的作用: ​ python中有很多各种不同的模块,每一个模块都可以帮助我们快速的实现一些功能 3.模块的导入方式: # 模块在使用…

雷达气象相关词汇(一 扫描模式)

参考自https://www.radartutorial.eu/15.weather/wr20.en.html https://en.wikipedia.org/wiki/Plan_position_indicator PPI(平面位置显示) A plan position indicator (PPI) is a type of radar display that represents the radar antenna in the center of the display, wi…

searchLights 动画

LOGO扫光效果.logo { width: 200px; height: 70px; display: flex; line-height: 70px; position: relative; overflow: hidden } .logo img { width: 100%; height: 70px } \3c p>.logo:before { } \3c br> @-webkit-keyframes searchLights { } \3c br> @-o-keyfram…

JavaWeb后端开发2024-08-08

Maven Apache Maven 是一个项目管理和构建工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建。Maven作用 依赖管理统一的项目结构项目构建仓库安装Maven<mirror> <id>alimaven</id> <name>aliyun maven</name> <u…