leetcode刷题记录(七十二)——146. LRU 缓存
(一)问题描述
146. LRU 缓存 - 力扣(LeetCode)146. LRU 缓存 - 请你设计并实现一个满足 LRU (最近最少使用) 缓存 [https://baike.baidu.com/item/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); // 返回 1lRUCache.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); // 返回 3lRUCache.get(4); // 返回 4 提示: * 1 <= capacity <= 3000 * 0 <= key <= 10000 * 0 <= value <= 105 * 最多调用 2 * 105 次 get 和 puthttps://leetcode.cn/problems/lru-cache/description/?envType=study-plan-v2&envId=top-100-liked
请你设计并实现一个满足 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
(二)解决思路
这道题以方便要用哈希表方便查找,另一方面可以用双向链表来记录节点被使用的顺序:新增的元素和刚刚被修改了value的元素放在头部,如果插入时节点数量超过了capacity,就把尾部元素删掉。使用双向链表和使用单向链表相比便于操作尾部元素。
方法一:使用现成的数据结构
python和java中都有存在哈希功能的链表结构,python是OrderedDict,java是LinkedHashMap。但是直接用已有的数据结构一般不会符合面试官的要求,和库函数的使用一样,有些数据结构的使用也要慎重,像这种直接用数据结构的情况明显是跳过了问题想要考察的重点。
下面的代码来自Leetcode官方题解。
class LRUCache extends LinkedHashMap<Integer, Integer>{private int capacity;public LRUCache(int capacity) {super(capacity, 0.75F, true);this.capacity = capacity;}public int get(int key) {return super.getOrDefault(key, -1);}public void put(int key, int value) {super.put(key, value);}@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {return size() > capacity; }
}
方法二:哈希表+双向链表
面试官会更希望我们自己实现哈希表+双向链表的功能。思路就是本节开头的那段话。链表的定义其实就是节点类的定义。为了方便插入和删除头尾元素,可以创建虚拟头尾节点head和tail。
class LRUCache {//双向链表class DLinkedNode{public int key;public int value;public DLinkedNode prev;public DLinkedNode next;public DLinkedNode(){};public DLinkedNode(int _key,int _value){key=_key;value=_value;}}//哈希表private HashMap<Integer,DLinkedNode> cache=new HashMap<>();//size是现在链表的长度,capacity是允许的最大节点数private int size;private int capacity;//虚拟头尾节点private DLinkedNode head,tail;public LRUCache(int capacity) {//大部分时候访问类自身的成员变量不需要this//但是如果方法里有某个局部变量和成员变量名字相同,就需要用this区分this.size=0;this.capacity=capacity;head=new DLinkedNode();tail=new DLinkedNode();head.next=tail;tail.prev=head;}public int get(int key) {//判断map里是否存在key,如果不存在的话会返回nullDLinkedNode node=cache.get(key);if(node==null){return -1;}else{//刚刚访问过的节点移动到头部moveToHead(node);return node.value;}}public void put(int key, int value) {//判断map里是否存在key,如果不存在的话会返回null//如果只是map存或者更新value的话不需要判断,但这里还涉及链表的变化,所以要判断DLinkedNode node=cache.get(key);if(node==null){//新节点加入DLinkedNode newNode=new DLinkedNode(key,value);//新节点放在链表头putToHead(newNode);//节点放进mapcache.put(key,newNode);size++;if(size>capacity){//超出容量,删除尾部节点int removeKey=removeFromTail();cache.remove(removeKey);}}else{//已经存在的节点更新值node.value=value;//放在节点头moveToHead(node);}}//节点的移动/添加就是指针指向的变化public void moveToHead(DLinkedNode node){node.prev.next=node.next;node.next.prev=node.prev;node.next=head.next;head.next.prev=node;head.next=node;node.prev=head;}public void putToHead(DLinkedNode newNode){head.next.prev=newNode;newNode.next=head.next;head.next=newNode;newNode.prev=head;}public int removeFromTail(){DLinkedNode node=tail.prev;node.next.prev=node.prev;node.prev.next=node.next;return node.key;}
}
注:大部分时候访问类自身的成员变量不需要this,但是如果方法里有某个局部变量和成员变量名字相同,就需要用this区分。
相关文章:

leetcode刷题记录(七十二)——146. LRU 缓存
(一)问题描述 146. LRU 缓存 - 力扣(LeetCode)146. LRU 缓存 - 请你设计并实现一个满足 LRU (最近最少使用) 缓存 [https://baike.baidu.com/item/LRU] 约束的数据结构。实现 LRUCache 类: * LRUCache(int capacity)…...

深圳大学-计算机系统(3)-实验一MIPS指令集实验
实验目标 a) 了解WinMIPS64的基本功能和作用; b) 熟悉MIPS指令、初步建立指令流水执行的感性认识; c) 掌握该工具的基本命令和操作,为流水线实验作准备。 实验内容 按照下面的实验步骤及说明,完成相关操作记录实验过程的截图&a…...

Java面试专题——面向对象
面向过程和面向对象的区别 面向过程:当事件比较简单的时候,利用面向过程,注重的是事件的具体的步骤/过程,注重的是过程中的具体的行为,以函数为最小单位,考虑怎么做。 面向对象:注重找“参与者…...

知行合一:解决有心无力的问题,解决知易行难的问题,知行合一并不意味着事事都要合一,而是....
问题是什么? 想学习的时候,有手机阻碍我们。想戒掉手机短视频,卸载后,几天的时间,又下载了回来。制定了减肥计划,但就是不执行。明知道这样做是不对的,但依然行动不起来。 沉溺于各种各样的享…...

Qt中自定义信号与槽
在学习信号和槽的时候,我们知道信号一般对应的就是用户的行为,槽指的是接受到信号后的响应,在类内有许多的内置信号和槽函数,能够去实现一些常见的行为,但实际业务开发中,尤其是接受到信号的响应会根据具体…...
.NET 8 项目 Docker 方式部署到 Linux 系统详细操作步骤
本文将详细介绍如何将一个 .NET 8 项目通过 Docker 部署到 Linux 系统中。以下步骤包括从项目的创建、Dockerfile 的编写、镜像构建、到最后在 Linux 上的容器运行。 1. 环境准备 在开始之前,请确保你已经具备以下环境: Linux 系统(如 Ubu…...
深入了解 Java split() 方法:分割字符串的利器
Java 提供的 split() 方法是 String 类中一个常用的工具,它可以将一个字符串根据指定的分隔符切割成多个子字符串,并以字符串数组的形式返回。这个方法常用于字符串的处理、数据解析等场景。本文将详细介绍 Java 中 split() 方法的使用方式,并…...
pgsql中处理数组类型字段
1、代码中存入和读取 需要使用自定义转换器 Slf4j public class ArrayTypeHandler extends BaseTypeHandler<List<String>> {Overridepublic void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType)throws SQL…...
如何正确定位前后端bug?
在平时的开发过程中,正确定位前后端bug是提高开发效率和项目质量的关键。以下是一些实用的方法。 一、前后端bug 特征 前端主要负责显示数据,后端主要负责处理数据、存储数据,前后端主要通过接口进行数据交换。 1.前端bug特征 界面显示类…...

mfc操作json示例
首先下载cJSON,加入项目; 构建工程,如果出现, fatal error C1010: unexpected end of file while looking for precompiled head 在cJSON.c文件的头部加入#include "stdafx.h"; 看情况,可能是加到.h或者是.cpp文件的头部,它如果有包含头文件, #include &…...

【技术总结类】2024,一场关于海量数据治理以及合理建模的系列写作
目录 1.今年的创作路线 2.先说第一条线 2.1.由日志引出的海量文本数据存储和分析问题 2.2.监控以及监控的可视化 2.3.数据量级再往上走牵扯出了大数据 2.4.由大数据牵扯出的JAVA线程高级内容 3.第二条线,也是2025要继续的主线 1.今年的创作路线 今年的写作内…...

Dockerfile另一种使用普通用户启动的方式
基础镜像的Dockerfile # 使用 Debian 11.9 的最小化版本作为基础镜像 FROM debian:11.11# 维护者信息 LABEL maintainer"caibingsen" # 复制自定义的 sources.list 文件(如果有的话) COPY sources.list /etc/apt/sources.list # 创建…...
python的pushbullet库在设备之间发送通知链接文件
Pushbullet 是一个非常方便的 Python 库,可以帮助你在设备之间发送通知、链接、文件等。以下是 Pushbullet 的一些主要功能和使用方法: 功能 与你的 Pushbullet 账户关联的设备(需要下载对应的pushbullet手机APP、电脑客户端)之…...

STM32之FreeRTOS开发介绍(十九)
STM32F407 系列文章 - freertos(十九) 目录 前言 一、简述 二、开源网址 三、原理及功能特性 1.原理简介 2.功能介绍 1.任务调度 2.任务管理 3.中断管理 4.消息队列 3.特点说明 4.优缺点 四、参考书籍 五、实现方式 总结 前言 FreeRTOS是…...

用java配合redis 在springboot上实现令牌桶算法
令牌桶算法配合 Redis 在 Java 中的应用令牌桶算法是一种常用的限流算法,适用于控制请求的频率,防止系统过载。结合 Redis 使用可以实现高效的分布式限流。 一.、引入依赖首先,需要在 pom.xml 文件中引入 spring-boot-starter-data-re…...

DCGAN - 深度卷积生成对抗网络:基于卷积神经网络的GAN
深度卷积生成对抗网络(DCGAN,Deep Convolutional Generative Adversarial Network)是生成对抗网络(GAN)的一种扩展,它通过使用卷积神经网络(CNN)来实现生成器和判别器的构建。与标准…...

51c~SLAM~合集1
我自己的原文哦~ https://blog.51cto.com/whaosoft/12327374 #GSLAM 自动驾驶相关~~~ 一个通用的SLAM架构和基准 GSLAM:A General SLAM Framework and Benchmark 开源代码:https://github.com/zdzhaoyong/GSLAM SLAM技术最近取得了许多成功&am…...
优化使用 Flask 构建视频转 GIF 工具
优化使用 Flask 构建视频转 GIF 工具 优化后的项目概述 在优化后的版本中,我们将实现以下功能: 可设置每个 GIF 的帧率和大小:用户可以选择 GIF 的帧率和输出大小。改进的用户界面:使用更现代的设计使界面更美观、整洁。自定义…...
spring cloud如何实现负载均衡
在Spring Cloud中,实际上并没有直接支持lb:\\这样的URL前缀来自动解析为负载均衡的服务地址。lb:\\这样的表示可能是在某些特定框架、文档或示例中自定义的,但它并不是Spring Cloud官方API或规范的一部分。 Spring Cloud实现负载均衡的方式通常依赖于服…...

leetcode19-删除链表的第n结点
leetcode 19 思路 要删除倒数第n个元素,那么就要找到倒数第n1个元素,那么我们需要两个指针来记录,首先快指针需要先走n1步,然后快慢指针一起进行移动,直到快指针为null的时候,此时慢指针恰好走到倒数第n…...
微信小程序前端面经
一、技术栈与编码能力(10min) 1. Vue 3 & Composition API Q1:请解释一下 ref 和 reactive 的区别?你在项目中是如何使用的? 答:ref是包装一个原始值或对象,通过.value访问,r…...
C++.OpenGL (3/64)着色器(Shader)深入
着色器(Shader)深入 着色器核心概念 #mermaid-svg-xC0jTt9mJWGVa7yE {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-xC0jTt9mJWGVa7yE .error-icon{fill:#552222;}#mermaid-svg-xC0jTt9mJWGVa7yE .error-text{fi…...
vue2使用笔记、vue2和vue3的区别
文章目录 vue2和vue3的区别1. 实现数据响应式的原理不同2. 生命周期不同3. vue 2.0 采用了 option 选项式 API,vue 3.0 采用了 composition 组合式 API4. 新特性编译宏5. 父子组件间双向数据绑定 v-model 不同6. v-for 和 v-if 优先级不同7. 使用的 diff 算法不同8.…...

A*算法实现原理以及实现步骤(C++)
算法原理: A*算法是一种启发式搜索算法,用于在图中寻找最短路径。它结合了Dijkstra算法的确保最短路径的优点和贪心最佳优先搜索的高效性。其核心在于使用一个评估函数: f(n) g(n) h(n) 其中: - g(n) 表示从起点到节点n的实际代…...

分析Web3下数据保护的创新模式
在这个信息爆炸的时代,我们正站在 Web3 的门槛上,迎接一个以去中心化、用户主权和数据隐私为核心的新时代。Web3 不仅仅是技术的迭代,它更是一场关于数据权利和责任的结构性变革。本文将探讨 Web3 下数据保护的创新模式,以期为用户…...
排序算法C语言实现
算法概览 排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性适用场景插入排序O(n)O(n)O(1)稳定小规模/基本有序希尔排序O(n log n)O(n)O(1)不稳定中等规模冒泡排序O(n)O(n)O(1)稳定教学/小规模堆排序O(n log n)O(n log n)O(1)不稳定大规模数据选择排序O(n)O(n)O(1)不稳定…...
逆向工程开篇(连载中)
项目特点 这个专栏专门设计用于汇编逆向工程研究,包含: ✅ 18个测试模块,覆盖所有主要C语言特性✅ 1200行工具类代码,400行主程序代码✅ 完整的Visual Studio 2017项目支持✅ Debug和Release两种构建配置✅ 静态库和可执行文件分…...
MCP协议在LLM系统中的架构与实现原理研究
MCP协议的角色和功能定位 模型上下文协议(Model Context Protocol, MCP) 是由Anthropic公司(Claude模型的发布方)提出的一种开放协议,旨在标准化大型语言模型(LLM)与外部数据源、工具和服务之间的交互方式。可以将MCP类比为AI应用的“USB-C接口”:通过统一的接口协议,…...
标识符Symbol和迭代器的实现
Symbol基础 Symbol("描述") 创建唯一标识符(每次调用返回新值) Symbol.for("key") 全局注册表模式(相同key返回同一Symbol) Symbol特性 作为对象属性键时:obj[SymbolKey] value不参与常规遍历&…...
ios版本的Tiktok二次安装不上,提示:Unable to Install “TikTok”
问题:Domain: IXUserPresentableErrorDomain Code: 1 Recovery Suggestion: Failed to load Info.plist from bundle at path /private/var/containers/Bundle/Application/E99D86D4-F96E-48F9-86C5-FE095A22E13A/DouyinDev.app/PlugIns/AwemeNotificationService.a…...