【链表】Leetcode 146. 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 ,则应该 逐出 最久未使用的关键字。
  • 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

示例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

解题思路

LRU Cache是一种常见的缓存替换策略,可以采用哈希表和双向链表结合的方式实现。 哈希表用于快速查找节点,双向链表用于记录访问顺序。

  • 1、使用HashMap来存储key和对应的节点。
  • 2、使用双向链表来存储缓存的数据,链表头部是最近使用的数据,链表尾部是最久未使用的数据。
  • 3、对于get操作,如果key存在于缓存中,将对应的节点移到链表头部,并返回value;否则返回-1。
  • 4、对于put操作,如果key已经存在于缓存中,更新对应的value,并将节点移到链表头部;如果key不存在于缓存中,插入新的节点到链表头部,判断是否超过容量,若超过容量,删除链表尾部的节点。
  • 5、删除节点时,需要同时在HashMap中删除对应的key。

java实现

public class LRUCache {class DLinkedNode {int key;int value;DLinkedNode prev;DLinkedNode next;}private HashMap<Integer, DLinkedNode> cache;private int size;private int capacity;private DLinkedNode head, tail;public LRUCache(int capacity) {this.cache = new HashMap<>();this.size = 0;this.capacity = capacity;this.head = new DLinkedNode();this.tail = new DLinkedNode();head.next = tail;tail.prev = head;}public int get(int key) {DLinkedNode node = cache.get(key);if (node == null) {return -1;}// 将访问的节点移动到链表头部moveToHead(node);return node.value;}public void put(int key, int value) {DLinkedNode node = cache.get(key);if (node == null) {// 如果key不存在,则创建新节点DLinkedNode newNode = new DLinkedNode();newNode.key = key;newNode.value = value;// 将新节点加入到链表头部cache.put(key, newNode);addToHead(newNode);size++;// 如果容量超限,则删除链表尾部节点if (size > capacity) {DLinkedNode tail = removeTail();cache.remove(tail.key);size--;}} else {// 如果key存在,则更新值,并将节点移到链表头部node.value = value;moveToHead(node);}}private void addToHead(DLinkedNode node) {node.prev = head;node.next = head.next;head.next.prev = node;head.next = node;}private void removeNode(DLinkedNode node) {node.prev.next = node.next;node.next.prev = node.prev;}private void moveToHead(DLinkedNode node) {removeNode(node);addToHead(node);}private DLinkedNode removeTail() {DLinkedNode res = tail.prev;removeNode(res);return res;}public static void main(String[] args) {// 创建容量为 2 的LRU缓存LRUCache lruCache = new LRUCache(2);// 插入 (1, 1)lruCache.put(1, 1);// 插入 (2, 2)lruCache.put(2, 2);// 获取键 1 的值,返回 1System.out.println(lruCache.get(1));// 插入 (3, 3),因为缓存容量为 2,需要移除最久未使用的键 2lruCache.put(3, 3);// 获取键 2 的值,返回 -1,因为键 2 已经被移除System.out.println(lruCache.get(2));// 插入 (4, 4),因为缓存容量为 2,需要移除最久未使用的键 1lruCache.put(4, 4);// 获取键 1 的值,返回 -1,因为键 1 已经被移除System.out.println(lruCache.get(1));// 获取键 3 的值,返回 3System.out.println(lruCache.get(3));// 获取键 4 的值,返回 4System.out.println(lruCache.get(4));}
}

时间空间复杂度

  • 时间复杂度:get和put操作均为O(1)的时间复杂度。
  • 空间复杂度:O(capacity),存储哈希表和双向链表所需的空间

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

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

相关文章

CTF题型 Python中pickle反序列化进阶利用例题opache绕过

CTF题型 pickle反序列化进阶&例题&opache绕过 文章目录 CTF题型 pickle反序列化进阶&例题&opache绕过一.基础的pickle反序列化例题1.[HFCTF 2021 Final]easyflask2.[0xgame 2023 Notebook]3.[[HZNUCTF 2023 preliminary\]pickle](https://www.nssctf.cn/proble…

大数据系列 | 使用Nginx作为数据采集接收端

大数据系列 | 使用Nginx作为数据采集接收端 1. 编译安装Nginx2. 通过程序对Nginx上传日志 1. 编译安装Nginx Nginx依赖包安装&#xff1a; rootnginx:~# apt install -y vim lua-devel gcc gcc-c autoconf automake zlib zlib-devel openssl openssl-devel gcc zlib1g-dev lib…

蓝桥杯java---螺旋矩阵

解题思路&#xff1a; int [][] arr new int[n][m];int i 0, j -1, temp 1;while (n * m > 0){for (int p 0; p < m; p)//从左自右arr[i][jj1] temp;n--;if (n * m 0) break;for (int p 0; p < n; p)//从上自下arr[ii1][j] temp;m--;if (n * m 0) break;fo…

分享一个免费查海关(HS)编码的工具

用过海关数据的朋友就会发现&#xff0c;因为现在大部分的海关数据都是国外的进口数据&#xff0c;所以如果要用海关编码去查相关产品的海关交易记录的话&#xff0c;最好的方法就是用当地的海关编码去搜。 各个国家的海关编码是不一样的&#xff0c;比如美国的一般是6-8位&am…

构造函数与析构函数

构造函数 每次创建类的新对象时执行构造函数的名称与类名相同&#xff0c;不带类型&#xff0c;可以有参数也可以没参数构造函数有时给成员函数付初值 析构函数 每次删除所创建的对象时执行析构函数与构造函数类似&#xff0c;前面多个~不带任何参数&#xff0c; #include …

【笔试】美团2024年春招第二场笔试(技术)

【笔试】美团2024年春招第二场笔试&#xff08;技术&#xff09; 文章目录 T1 模拟T2 模拟T3 模拟&#xff0c;快速幂/打表T4 众数、前缀和、树状数组T5 逆序对&#xff0c;树状数组 T1 模拟 题目&#xff1a;数组求和&#xff0c;判断是否要减一个数 思路&#xff1a;模拟即可…

FPGA时钟资源详解(3)——全局时钟资源

FPGA时钟系列文章总览&#xff1a;FPGA原理与结构&#xff08;14&#xff09;——时钟资源https://ztzhang.blog.csdn.net/article/details/132307564 一、概述 全局时钟是 FPGA 中的一种专用互连网络&#xff0c;旨在将时钟信号分配到 FPGA 内各种资源的时钟输入处。这种设计…

如何查看ubuntu服务器上防火墙信息

1、检查防火墙状态&#xff1a; Ubuntu 18.04及更高版本使用的是ufw&#xff08;Uncomplicated Firewall&#xff09;。您可以使用以下命令检查ufw是否已安装并处于运行状态&#xff1a; sudo ufw status如果ufw已安装并正在运行&#xff0c;则会显示防火墙的状态&#xff08…

使用Shell脚本进行MySql权限修改

背景&#xff1a;原先数据配置文件中有bind-address127.0.0.1&#xff0c;注释掉此配置后&#xff0c;原数据库中默认带%root的权限&#xff0c;现在需要通过脚本实现白名单列表中的ip添加权限允许访问数据库&#xff0c;白名单之外的ip没有权限访问数据库。 以下是过程中记录的…

免费redis可视化工具windows/mac都可以使用,开源免费

官方地址&#xff1a;RedisInsight | The Best Redis GUI github开源地址&#xff1a;GitHub - RedisInsight/RedisDesktopManager Redis Desktop Manager – Redis可视化管理工具、redis图形化管理工具、redis可视化客户端、redis集群管理工具。 官方下载方式 滚动到页面底…

FPGA时钟资源详解(4)——区域时钟资源

FPGA时钟系列文章总览&#xff1a;FPGA原理与结构&#xff08;14&#xff09;——时钟资源https://ztzhang.blog.csdn.net/article/details/132307564 目录 一、概述 二、Clock-Capable I/O 三、I/O 时钟缓冲器 —— BUFIO 3.1 I/O 时钟缓冲器 3.2 BUFIO原语 四、区域时钟…

mybatisplus和mybatis兼容问题

Invalid bound statement (not found) 错误 原xml配置 <bean id"sqlSessionFactory" class"org.mybatis.spring.SqlSessionFactoryBean"><property name"mapperLocations" value"classpath:/META-INF/mapper/*.xml"/>&l…

Vue3——如何实现页面访问拦截

引言 在现代的Web开发中&#xff0c;页面访问拦截是一个非常常见的需求。通过拦截页面访问&#xff0c;我们可以控制用户在访问特定页面之前需要满足的条件&#xff0c;比如登录状态、权限等。Vue是一个非常流行的JavaScript框架&#xff0c;它提供了许多强大的工具和功能&…

ruoyi-nbcio-plus基于vue3的flowable多实例审批单元的升级修改

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…

High 级别反射型 XSS 攻击演示(附链接)

环境准备 如何搭建 DVWA 靶场保姆级教程&#xff08;附链接&#xff09;https://eclecticism.blog.csdn.net/article/details/135834194?spm1001.2014.3001.5502 测试 打开靶场找到该漏洞页面 先右键检查输入框属性 还是和之前一样的&#xff0c;所以直接输入 HTML 标签提交…

Vue 发送Ajax请求多种方式

1. 发送ajax请求的方式 方案一&#xff1a;jq 的ajax&#xff08;在 vue 中不推荐同时使用&#xff09;方案二&#xff1a;js 原始官方 fetch方法方案三&#xff1a;axios 第三方 2. 方案一 后端视图函数 from rest_framework.viewsets import ViewSet from rest_framework…

Rust 实战练习 - 7. FFI, 库, ABI, libc

FFI FFI&#xff08;Foreign Function Interface&#xff09;是这样一种机制&#xff1a;用一种编程语言写的程序能调用另一种编程语言写的函数&#xff08;routines&#xff09;。 调用约定&#xff0c;类型表示和名称修饰这三者的统称&#xff0c;即是众所周知的应用二进制…

云数据库认识

云数据库概述 说明云数据库厂商概述Amazon 云数据库产品Google 的云数据库产品Microsoft 的云数据库产品 云数据库系统架构UMP 系统概述UMP 系统架构MnesiaRabbitMQZooKeeperLVSController 服务器Proxy 服务器Agent 服务器日志分析服务器 UMP 系统功能容灾 读写分离分库分表资源…

刚删除的文件怎么找回?刚删除的文件重新找回方法

电脑是我们办公、生活和娱乐必不可缺少的设备,里面存储着我们很多重要的文件。但是,有时候我们不小心误删了文件,或者是不小心删除了一些重要的数据等,要怎么进行恢复呢?今天,小编就专门给大家讲下刚删除的文件重新找回方法。 方法一: 文件不小心删除了,请立即停止对硬…