面试遇到算法题:实现LRU缓存

news/2024/5/18 17:32:45

请你设计并实现一个满足 LRU (最近最少使用) 缓存约束的数据结构。

这是一道大厂面试高频出现的算法题,难度为⭐️⭐️⭐️,属于中等,老铁们来一起看看这个题该怎么解?

1. 原题再现

没有废话,翠花,上酸菜!

2. 具体实现

为了实现一个满足 LRU (最近最少使用)缓存约束的数据结构,我们需要一个能够快速访问、更新和删除的数据结构,V 哥想到了用哈希表,因为哈希表提供了快速的查找能力,但是它不能保持元素的顺序;而双向链表可以保持元素的顺序,并且可以在 O(1) 时间复杂度内进行插入和删除操作。因此, V哥采用结合使用哈希表和双向链表来实现LRU缓存。

以下是 Java 代码实现:

import java.util.HashMap;class Node {int key;int value;Node prev;Node next;public Node(int key, int value) {this.key = key;this.value = value;}
}public class LRUCache {private HashMap<Integer, Node> cache;private Node head, tail;private int capacity;private int count;public LRUCache(int capacity) {this.capacity = capacity;this.cache = new HashMap<>();this.head = new Node(0, 0);this.tail = new Node(0, 0);this.head.next = this.tail;this.tail.prev = this.head;this.count = 0;}public int get(int key) {Node node = cache.get(key);if (node == null) {return -1;}moveToHead(node);return node.value;}public void put(int key, int value) {Node node = cache.get(key);if (node == null) {Node newNode = new Node(key, value);cache.put(key, newNode);addNode(newNode);count++;if (count > capacity) {Node toDel = popTail();cache.remove(toDel.key);count--;}} else {node.value = value;moveToHead(node);}}private void addNode(Node node) {node.prev = head;node.next = head.next;head.next.prev = node;head.next = node;}private void removeNode(Node node) {node.prev.next = node.next;node.next.prev = node.prev;}private void moveToHead(Node node) {removeNode(node);addNode(node);}private Node popTail() {Node res = tail.prev;removeNode(res);return res;}
}

使用示例:

public class Main {public static void main(String[] args) {LRUCache lRUCache = new LRUCache(2);lRUCache.put(1, 1); // 缓存是 {1=1}lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}System.out.println(lRUCache.get(1));    // 返回 1lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}System.out.println(lRUCache.get(2));    // 返回 -1 (未找到)lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}System.out.println(lRUCache.get(1));    // 返回 -1 (未找到)System.out.println(lRUCache.get(3));    // 返回 3System.out.println(lRUCache.get(4));    // 返回 4}
}

输出结果应该与题目中的示例输出一致。这个实现使用了哈希表来快速查找节点,同时使用双向链表来维护节点的顺序和实现快速插入和删除操作。这样,我们就可以在 O(1) 的时间复杂度内完成 get 和 put 操作。

实现过程和步骤如下:

  1. 定义一个 Node 类,用于双向链表的节点,包含 key、value 以及前驱和后继节点的引用。

  2. 在 LRUCache 类中,定义一个 capacity 表示缓存的最大容量,一个 count 表示当前缓存中的节点数量,一个 cache 哈希表用于存储键和节点的映射,以及 head 和 tail 虚拟节点用于简化双向链表的操作。

  3. 实现 get 方法,首先在哈希表中查找键对应的节点,如果节点不存在,返回 -1。如果节点存在,则将该节点移动到链表的头部,表示最近被使用,然后返回节点的值。

  4. 实现 put 方法,如果键在哈希表中不存在,创建一个新的节点,并将其添加到链表的头部,同时添加到哈希表中。如果插入后节点数量超过了容量,则需要移除链表尾部的节点,并从哈希表中删除对应的条目。如果键已经存在,则更新对应的节点值,并将其移动到链表头部。

  5. addNode 方法用于将节点添加到链表头部,removeNode 方法用于从链表中移除节点,moveToHead 方法用于将节点移动到链表头部,popTail 方法用于移除链表尾部的节点。

  6. 在 Main 类的 main 方法中,我们创建了一个 LRUCache 实例,并执行了一系列的 put 和 get 操作来演示其功能。

V哥认为这个实现确保了 get 和 put 操作的平均时间复杂度为O(1)。get 操作直接通过哈希表查找节点,而 put 操作中,无论是更新现有节点还是添加新节点,都涉及到对双向链表的操作,这些操作的时间复杂度都是 O(1)。当缓存达到容量上限时,put 操作会移除最久未使用的节点,这也是 O(1) 时间复杂度的操作。

3. 小结一下

V哥的这个实现的关键在于维护一个双向链表,它可以帮助我们快速地访问、更新和删除最近最少使用的节点,同时使用哈希表来提供快速的查找能力。这样,我们就可以在 O(1) 的时间复杂度内完成所有的缓存操作。哈哈干净利索,回答完毕。


http://www.mrgr.cn/p/63478676

相关文章

数据结构系列-堆排序当中的T-TOK问题

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 之前我们讲到了堆排序的实现逻辑&#xff0c;那么接下来我们重点关注的就是其中的T-TOK问题 T-TOK说简单点&#xff0c;就是说&#xff0c;假如有10000个数据&#xff08;随机的…

揭开ChatGPT面纱(3):使用OpenAI进行文本情感分析(embeddings接口)

文章目录 一、embeddings接口解析二、代码实现1.数据集dataset.csv2.代码3.运行结果 openai版本1.6.1 本系列博客源码仓库&#xff1a;gitlab&#xff0c;本博客对应文件夹03 在这一篇博客中我将使用OpenAI的embeddings接口判断21条服装评价是否是好评。 首先来看实现思路&am…

golang学习笔记(defer基础知识)

什么是defer defer语句用于golang程序中延迟函数的调用&#xff0c; 每次defer都会把一个函数压入栈中&#xff0c; 函数返回前再把延迟的函数取出并执行。 为了方便描述&#xff0c; 我们把创建defer的函数称为主函数&#xff0c; defer语句后面的函数称为延迟函数。延迟函数…

重回铁王座!时隔5年!Quill 2.0 终于发布啦

2024年4月17日,Quill 2.0 正式发布🎉期待了5年,我怀着激动的心情立马升级体验了下,本文我就带大家一起看看 Quill 2.0 有哪些重大更新。你好,我是 Kagol。 2024年4月17日,Quill 2.0 正式发布🎉 最后一个 1.0 版本 1.3.7 发布于 2019年9月9日,时隔4年零7个月。 富文本…

Adobe Illustrator 2024 v28.4.1 (macOS, Windows) - 矢量绘图

Adobe Illustrator 2024 v28.4.1 (macOS, Windows) - 矢量绘图 Acrobat、After Effects、Animate、Audition、Bridge、Character Animator、Dimension、Dreamweaver、Illustrator、InCopy、InDesign、Lightroom Classic、Media Encoder、Photoshop、Premiere Pro、Adobe XD 请…

Git之merge与rebase操作命令及问题

背景&#xff1a;之前一直使用的是 merge 来实现两分支的合并代码操作&#xff0c;遇到冲突&#xff0c;解决完冲突从头 add 、commit 、push 再次操作一遍提交操作就没啥事了。但后来的大型项目是 多人协同开发&#xff0c;前端带头人提议倡导使用 rebase 来合并分支&#xff…

推荐|免费ssl通配符证书https通配符证书平台,性价比超高的证书

在网络安全日益重要的今天,选择一个可靠的SSL证书平台至关重要。Spug证书平台以其高性价比、专业服务、便捷操作,以及独有的无限免费通配符证书申请功能,成为了您的理想选择。 网址:ssl.spug.cc 为什么选择Spug证书平台?免费通配符:支持免费申请通配符证书,为您的多子站…

Pytorch手撸Attention

Pytorch手撸Attention 注释写的很详细了&#xff0c;对照着公式比较下更好理解&#xff0c;可以参考一下知乎的文章 注意力机制 import torch import torch.nn as nn import torch.nn.functional as Fclass SelfAttention(nn.Module):def __init__(self, embed_size):super(S…

架构师核心-云计算云上实战(云计算基础、云服务器ECS、云设施实战、云上高并发Web架构)

文章目录 云计算基础1. 概念1. 云平台优势2. 公有云3. 私有云4. IaaS、PaaS、SaaS 2. 云设施1. 概览2. 核心组件 云服务器ECS1. ECS介绍1. 简介2. 组件3. 概念4. 图解5. 规格6. 场景 2. ECS服务器开通1. 开通服务器2. 连接服务器 3. 云部署准备1. 1Panel介绍2. 安装1Panel3.安全…

读天才与算法:人脑与AI的数学思维笔记09_分形

分形1. 分形 1.1. 1904年,瑞典数学家科赫(Helge von Koch)首次发表了雪花图案的结构——科赫曲线(又称雪花曲线),它被认为是一种数学怪胎,一种奇怪的人工构造 1.1.1. 但实际上并不是,自然界中到处都是以分形结构存在着的图形 1.1.2. 既不能说科赫曲线是一维的,也不能说…

C/C++程序设计实验报告4 | 函数实验

本文整理自博主本科大一《C/C程序设计》专业课的课内实验报告&#xff0c;适合C语言初学者们学习、练习。 编译器&#xff1a;gcc 10.3.0 ---- 注&#xff1a; 1.虽然课程名为C程序设计&#xff0c;但实际上当时校内该课的内容大部分其实都是C语言&#xff0c;C的元素最多可能只…

[转帖] 银河麒麟系统安全机制-KYSEC

https://zhuanlan.zhihu.com/p/349663329 麒麟系统为什么称为国内最安全的Linux系统?秘密就在于KYSEC,麒麟系统安全机制。一般情况下Linux下默认的接入控制是DAC,其特点是资源的拥有者可以对他进行任何操作(读、写、执行)。当一个进程准备操作资源时,Linux内核会比较进程…

[转帖]数据库系列之简要对比下GaussDB和OpenGauss数据库

https://blog.csdn.net/solihawk/article/details/134939941GaussDB作为一款企业级的数据库产品,和开源数据库OpenGauss之间又是什么样的关系,刚开始接触的时候是一头雾水,因此本文简要对比下二者的区别,以加深了解。 1、GaussDB和OpenGauss数据库简要对比 GaussDB是华为基…

分布式与一致性协议之CAP(二)

CAP CAP不可能三角 CAP不可能三角是指对于一个分布式系统而言&#xff0c;一致性、可用性、分区容错性指标不可兼得&#xff0c;只能从中选择两个&#xff0c; 如图所示。CAP不可能三角最初是埃里克布鲁尔(Eric Brewer)基于自己的工程实践提出的一个猜想&#xff0c;后被塞斯吉…

如何在CentOS搭建docker compose ui可视化工具并无公网IP远程管理容器

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

在一台笔记本电脑上试用Ubuntu22.04

在一台笔记本电脑上试用Ubuntu22.04。 本来想看以下该操作系统能否识别笔记本电脑上的硬盘&#xff0c;于是下载试一下。选了一个国内镜像网站下载。下载速度很快。下载以后用软件win image 将下载的iso文件写到U盘上&#xff0c;用的是usb2.0的U盘&#xff0c;该操作用时11分…

【八股】计算机网络篇

网络模型 应用层【HTTP&#x1f449;报文/消息】 传输层【TCP或UDP&#x1f449;段&#x1f449;MSS】网络层【IP、寻址和路由&#x1f449;MTU】 ①IP&#xff08;Internet Protocol&#xff0c;网际协议&#xff09;主要作用是定义数据包的格式、对数据包进行路由和寻址&…

9.Eureka服务发现+Ribbon+RestTemplate服务调用

order-service服务通过服务名称来代替 ip:port的方式访问user-service服务的接口。 原来的请求代码&#xff1a; Service public class OrderServiceImpl implements OrderService {Autowiredprivate OrderMapper orderMapper;Autowiredprivate RestTemplate restTemplate;Ov…

深度学习中的熵、交叉熵、相对熵(KL散度)、极大释然估计之间的联系与区别

熵的最初来源于热力学。在热力学中&#xff0c;熵代表了系统的无序程度或混乱程度&#xff0c;也可以理解为系统的热力学状态的一种度量。后来被广泛引用于各个领域中&#xff0c;如信息学、统计学、AI等&#xff0c;甚至社会学当中。接下来将大家领略一下深度学习中熵的应用。…

npm、yarn与pnpm详解

&#x1f525; npm、yarn与pnpm详解 &#x1f516; 一、npm &#x1f50d; 简介&#xff1a; npm是随Node.js一起安装的官方包管理工具&#xff0c;它为开发者搭建了一个庞大的资源库&#xff0c;允许他们在这个平台上搜索、安装和管理项目所必需的各种代码库或模块。 &#…