学习记录:js算法(三十三):LRU 缓存

news/2024/9/19 18:44:03/ 标签: 学习, javascript, 算法

文章目录

    • LRU 缓存
      • 网上思路
    • 总结

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 ,则应该 逐出 最久未使用的关键字。

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

我的思路
题目看的我一头雾水,一点思路没有,还去查了什么是 [LRU],最后还是没看懂。。。(https://baike.baidu.com/item/LRU)
网上思路
哈希表

网上思路

class Node {constructor(key, value) {this.key = key;this.value = value;this.prev = null;this.next = null;}
}class LRUCache {constructor(capacity) {this.capacity = capacity;this.hash = new Map(); // 用于快速查找this.head = new Node(); // 链表头节点,不存储数据this.tail = new Node(); // 链表尾节点,不存储数据this.head.next = this.tail;this.tail.prev = this.head;}get(key) {if (this.hash.has(key)) {const node = this.hash.get(key);this.moveToHead(node); // 将访问的节点移到链表头部return node.value;}return -1;}put(key, value) {if (this.hash.has(key)) {const node = this.hash.get(key);node.value = value; // 更新值this.moveToHead(node); // 移到头部} else {const newNode = new Node(key, value);this.hash.set(key, newNode);this.addToHead(newNode); // 插入到头部if (this.hash.size > this.capacity) {// 超出容量,删除尾部节点const removedNode = this.removeTail();this.hash.delete(removedNode.key);}}}moveToHead(node) {this.removeNode(node);this.addToHead(node);}addToHead(node) {node.prev = this.head;node.next = this.head.next;this.head.next.prev = node;this.head.next = node;}removeNode(node) {node.prev.next = node.next;node.next.prev = node.prev;}removeTail() {const removedNode = this.tail.prev;this.removeNode(removedNode);return removedNode;}
}
// 这段代码首先定义了一个Node类来表示缓存中的每一个键值对,包含了指向前后节点的指针。
// LRUCache类则实现了LRU缓存的所有功能,包括使用哈希表快速查找,以及通过双向链表来维护元素的使用顺序。
// get和put方法均能在平均时间复杂度O(1)内完成操作。// 或者使用以下代码
/*** @param {number} capacity*/
var LRUCache = function(capacity) {this.capacity = capacity;this.hash = new Map();this.head = new Node();this.tail = new Node();this.head.next = this.tail;this.tail.prev = this.head;
};/** * @param {number} key* @return {number}*/
LRUCache.prototype.get = function(key) {if (this.hash.has(key)) {const node = this.hash.get(key);this.moveToHead(node);return node.value;}return -1;
};/** * @param {number} key * @param {number} value* @return {void}*/
LRUCache.prototype.put = function(key, value) {if (this.hash.has(key)) {const node = this.hash.get(key);node.value = value;this.moveToHead(node);} else {const newNode = new Node(key, value);this.hash.set(key, newNode);this.addToHead(newNode);if (this.hash.size > this.capacity) {const removedNode = this.removeTail();this.hash.delete(removedNode.key);}}
};LRUCache.prototype.moveToHead = function(node) {this.removeNode(node);this.addToHead(node);
};LRUCache.prototype.addToHead = function(node) {node.prev = this.head;node.next = this.head.next;this.head.next.prev = node;this.head.next = node;
};LRUCache.prototype.removeNode = function(node) {node.prev.next = node.next;node.next.prev = node.prev;
};LRUCache.prototype.removeTail = function() {const removedNode = this.tail.prev;this.removeNode(removedNode);return removedNode;
};// Node类定义保持不变
class Node {constructor(key, value) {this.key = key;this.value = value;this.prev = null;this.next = null;}
}

讲解
要实现 LRU 缓存,我们可以使用哈希表(在 JavaScript 中是对象或 Map )和双向链表来完成。双向链表用于存储缓存项,确保插入、删除操作的高效性,而哈希表用于快速查找缓存项在链表中的位置。

  1. 数据结构选择:
    ○ 哈希表:快速查找键值对,时间复杂度O(1)。
    ○ 双向链表:快速在头部添加和尾部删除元素,符合 LRU 特性。
  2. 实现逻辑:
    get(key) 操作:如果 key 存在于哈希表中,将对应节点移到链表头部,并返回其值;否则返回-1。
    put(key, value) 操作:如果 key 已存在,更新其值并移到链表头部;如果key 不存在且缓存已满,删除链表尾部节点(即最久未使用的项),然后在链表头部插入新的 key-value 对。

总结

今天纯摆烂,把网上的思路贴上来,也没搞懂。。。


http://www.ppmy.cn/news/1526922.html

相关文章

TypeScript:高级类型

一、交叉类型(Intersection Types) 交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。 例如, Person & Serializable & Loggable同时是 Person …

华为OD机试真题-服务器广播-2024年OD统一考试(E卷)

最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客 题目描述 服务器连接方式包括直接相连,间接相连。A和B直接连接,B和C直接连接,则A和C间接连接直接连接和间接连接都可以发送广播。 给出一个 N*N 数组,代表 N 个服务器 matrix…

Java-数据结构-二叉树-习题(一) (✪ω✪)

文本目录: ❄️一、习题一(检查两颗树是否相同): ▶ 思路: ▶ 代码: ❄️二、习题二(另一棵树的子树): ▶ 思路: ▶ 代码: ❄️三、习题三(翻转二叉树): ▶ 思路: ▶ 代…

ThreadX源码:Cortex-A7的tx_thread_irq_nesting_start(嵌套中断开始动作).s汇编代码分析

0 参考资料 Cortex M3权威指南(中文).pdf(可以参考ARM指令集用法) 1 前言 tx_thread_irq_nesting_start.s是用来实现Cortex-A7 IRQ嵌套中断的开始函数实现的汇编文件。 2 源码分析 源码如下: 1  IRQ_DISABLE 0x80…

网络安全(黑客技术)2024年三个月自学手册

🤟 基于入门网络安全/黑客打造的:👉黑客&网络安全入门&进阶学习资源包 前言 什么是网络安全 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、…

Linux系统应用之知识补充——OpenEuler(欧拉)的安装和基础配置

前言 这篇文章将会对OpenEuler的安装进行详解,一步一步跟着走下去就可以成功 注意 :以下的指令操作最好在root权限下进行(即su - root) ☀️工贵其久,业贵其专! 1、OpenEuler的安装 这里我不过多介绍&a…

OCR2.0--General OCR Theory

引领光学字符识别(OCR)的新篇章 引言:OCR技术进化的必要性 光学字符识别(OCR)是一项广泛应用的技术,它能够从图像中提取字符并将其转换为可编辑格式。虽然OCR-1.0在过去取得了广泛应用,但传统…

华为初级认证HCIA怎么样?

想在网络技术领域实现职业突破吗?华为HCIA初级认证是专为网络领域的新手与初学者设计的一项入门级认证。它旨在评估并确认个人对网络基本原理和技术知识的扎实掌握,是步入华为认证体系大门的基石。 一、华为HCIA 初级认证概述 华为初级认证网络工程师&am…

【ESP32】Arduino开发 | 中断矩阵+按键输入中断例程

对于中断矩阵的详细介绍会放在ESP-IDF开发文章中,跳转栏目目录可以找到对应文章。 1. API 1.1 绑定GPIO中断 attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode); pin:管脚号;handler:中断处理函数;mode…

【百日算法计划】:每日一题,见证成长(014)

题目 奇偶链表 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起 示例: 输入: 2->1->3->5->6->4->7->NULL 输出: 2->3->6->7->1->5->4->NULL 思路 构建两个结果链表,分别存储奇偶节点 使用一个辅助变…

初识爬虫1

学习路线:爬虫基础知识-requests模块-数据提取-selenium-反爬与反反爬-MongoDB数据库-scrapy-appium。 对应视频链接(百度网盘):正在整理中 爬虫基础知识: 1.爬虫的概念 总结:模拟浏览器,发送请求,获取…

vue项目本地可以访问接口,浏览器输入接口可以访问数据,部署到服务器无法报接口404

需求变动,原本访问python的后端接口,现在新增Java的接口 新增的接口在服务器上一直404 ,本地正常,浏览器输入路径正常。 两个后端不同端口,前端配置了两个转发如下: dev: {// PathsassetsSubDirectory: st…

uni-app plus.runtime.arguments 获取参数

uni-app plus.runtime.arguments 获取参数 问题 在 app.vue 中 onShow 获取 应用启动的参数:plus.runtime.arguments 这个是可行的. APP打开以后, 进入到了后台 然后再恢复到前台 仍然会走一次 onShow的生命周期 然后获取到plus.runtime.arguments 中的参数&#x…

Linux:vim编辑技巧

命令模式 光标跳转 输入18,再输入G,可以跳转到18行。 复制、粘贴、删除 P是往上一行粘贴 小写u可以撤销 查找/撤销/保存 大写U可能失效,用CTRLr 末行模式 保存/退出/文件操作 字符串替换 开关参数的控制

CentOS入门宝典:从零到一构建你的Linux服务器帝国

目录 引言 一、CentOS简介与版本选择 1.1 CentOS是什么? 1.2 版本选择 二、安装CentOS 2.1 准备安装介质 2.2 安装过程 三、基础配置与优化 3.1 更新系统 3.2 配置防火墙 3.3 配置SELinux 3.4 系统监控与日志 四、网络配置与管理 4.1 配置静态IP 4.…

解决LineageOS提示网络受限问题

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/ 问题原因 由于 LineageOS 源码里默认是使用 google captive连接验证服务,所以国内会一直提示网络受限,但是实际上是可以访问网络的。 …

nginx安装及vue项目部署

安装及简单配置 在usr/local下建好nginx文件夹,下载好nginx-1.26.2.tar.gz压缩文件.安装编译工具及库文件 yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel pcre-devel gcc、gcc-c # 主要用来进行编译相关使用 openssl、ope…

MAVEN如何导入项目

工作中经常需要导入他人的项目,那么如何导入呢? 1, 选择Maven面板,点 2,选中对应项目的pom.xml,双击即可 3,如果没有maven面板,可以选择view->Appearnce->Tool Window Bars…

C#使用TCP-S7协议读写西门子PLC(三)

接上篇 C#使用TCP-S7协议读写西门子PLC(二)-CSDN博客 这里我们进行封装读写西门子PLC的S7协议命令以及连接西门子PLC并两次握手 新建部分类文件SiemensS7ProtocolUtil.ReadWrite.cs 主要方法: 连接西门子PLC并发送两次握手。两次握手成功后,才真正连…

Invoke-Maldaptive:一款针对LDAP SearchFilter的安全分析工具

关于Invoke-Maldaptive MaLDAPtive 是一款针对LDAP SearchFilter的安全分析工具,旨在用于对LDAP SearchFilter 执行安全解析、混淆、反混淆和安全检测。 其基础是 100% 定制的 C# LDAP 解析器,该解析器处理标记化和语法树解析以及众多自定义属性&#x…