lc146LRU缓存——模仿LinkedHashMap

news2024/12/16 3:19:14

146. LRU 缓存 - 力扣(LeetCode)

法1:

调用java现有的LinkedHashMap的方法,但不太理解反正都不需要扩容,super(capacity, 1F, true);不行吗,干嘛还弄个装载因子0.75还中途扩容一次浪费时间。

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);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
        return size() > capacity; 
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/lru-cache/solutions/259678/lruhuan-cun-ji-zhi-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

法2:

要实现O(1)的get和put,那得用哈希表但手撸一个哈希难度太大,应该不至于考那么过分,那就基于使用现有map的前提下实现LRU缓存。关键是要记录最近最少使用的是哪一个,那么需要每次将最新使用的放到“最后面”,这样每次取“最前面”那个进行淘汰就是最近最少使用的。那么采用双向链表比较合适,队列,栈又不能从中间取元素;数组从中间移动到最前面,移动太多,时间复杂度高;单向链表的话需要知道被移动元素的前一个元素才方便移动,所以最后相比之下双向链表最合适。 

双向链表放哪些内容呢,前后指针是要放的,value是要放的,key也需要因为当容量满了要删除map中head指向的节点,那么就要从这个双向链表节点中获取到key才行。

另外可以使用哑结点技巧,即head,tail都用一个不存value的空节点表示,也叫伪头结点,伪尾结点。这样有很多好处,1.当你尾插入时,正常不用哑结点要分3种情况讨论,(1)插入时,链表为空,head,tail都为空;(2)head=tail时即仅一个节点时(3)2个即以上节点时(正常情况时),

2,当删除链表中head时,也要分2种情况,(1)capacity为1时,head = tail;(2)正常情况;

当使用哑结点技巧后,尾插和删除head都只用1种情况处理,简化太多。

class LRUCache {
    class DoubleLinkedList {
        int key; //不存key,到时候不好删除
        int val;
        DoubleLinkedList prev;
        DoubleLinkedList next;

        public DoubleLinkedList() {};
        public DoubleLinkedList(int key, int val) {
            this.key = key;
            this.val = val;
        }
    };

    private Map<Integer, DoubleLinkedList> map;
    private DoubleLinkedList head;
    private DoubleLinkedList tail;
    private int capacity;
    private int size;

    public LRUCache(int capacity) {
        map = new HashMap<Integer, DoubleLinkedList>(capacity, 1F);
        //哑结点
        head = new DoubleLinkedList();
        tail = new DoubleLinkedList();
        head.next = tail;
        tail.prev = head;
        this.capacity = capacity;
        size = 0;
    }
    
    public int get(int key) {
        if(!map.containsKey(key)) {
            return -1;
        }

        //含有,则1.更新到链表末尾,2.返回
        DoubleLinkedList node = map.get(key);
        //更新到链表尾部
        move2Tail(node);

        return node.val;
    }
    
    public void put(int key, int value) {
        //1.之前就存在
        if(map.containsKey(key)) {
            DoubleLinkedList node = map.get(key);
            node.val = value;
            //更新最新使用
            move2Tail(node);
            return;
        } else if(size < capacity) {
            //2.容量没满 新添加
            add(key, value);
            size++;
            return;
        } 
        // 3.满了需要替换
        //3.1删除最久没使用的
        //tail末尾也搞个哑结点,不然capacity为1时,删除时还要考虑head.next.next为空的情况
        map.remove(head.next.key);
        deleteNode(head.next);
        // 3.2新添加进map
        add(key, value);
    }

    //更新最新使用,移到链表尾部
    public void move2Tail(DoubleLinkedList node) {
        //正常分3种情况,1.是head,2.在中间,3.本就在tail
        //利用头部和尾部哑结点,头,尾结点先用一个没有实际意义的节点,就可以1,2,3情况全合并了

        // 1.原链表中先删除节点
        deleteNode(node);
        // 2.插入到末尾
        insert2Tail(node);
    }

    //从链表中删除节点
    public void deleteNode(DoubleLinkedList node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    //新增map节点
    public void add(int key, int value) {
        DoubleLinkedList newNode = new DoubleLinkedList(key, value);
        //用了尾部哑结点,就不管是不是第一次插入都同样处理了
        map.put(key, newNode);
        insert2Tail(newNode);
    }

    //插入到尾部
    public void insert2Tail(DoubleLinkedList node) {
        node.prev = tail.prev;
        tail.prev.next = node;
        node.next = tail;
        tail.prev = node;
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

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

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

相关文章

【HF设计模式】03-装饰者模式

声明&#xff1a;仅为个人学习总结&#xff0c;还请批判性查看&#xff0c;如有不同观点&#xff0c;欢迎交流。 摘要 《Head First设计模式》第3章笔记&#xff1a;结合示例应用和代码&#xff0c;介绍装饰者模式&#xff0c;包括遇到的问题、遵循的 OO 原则、达到的效果。 …

Linux查看是否有www-data用户,如果没有添加一个

在 Linux 系统中&#xff0c;www-data 用户通常是用来运行 Web 服务&#xff08;如 Nginx 或 Apache&#xff09;的。如果你想检查系统中是否已经存在 www-data 用户&#xff0c;并在没有的情况下添加一个&#xff0c;可以按照以下步骤操作&#xff1a; ### 1. 检查 www-data …

23.模块和包

模块 模块Module,是一个python文件&#xff0c;以.py结尾。 模块能定义函数、类和变量。 模块导入 模块在使用前需要先导入 [from 模块名] import [模块 | 类 | 变量 | 函数 | *] [as 别名] import 模块 import time print("start...") time.sleep(5) print(&…

IDEA报错:无效的源发行版、无效的目标发行版

1. 无效的源发行版 创建项目的时候&#xff0c;会遇见这个报错&#xff0c;原因就是编译的JDK版本与发布版本不一致。 解决方法&#xff1a; 1.1. 找到问题所在地 英文&#xff1a;File -> Project Structure ->Project Settings 中文&#xff1a;文件->项目结构 …

2025年,客服知识库与人工智能的结合

随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;传统客服模式正在经历前所未有的变革。特别是在2025年&#xff0c;客服知识库与AI的深度融合&#xff0c;不仅极大地提升了客服处理的效率与准确性&#xff0c;还为用户带来了更加个性化、高效的服务体验。 …

JVM 双亲委派模型以及垃圾回收机制

目录 1. JVM 内存区域划分 2. JVM 中类加载的过程 1) 类加载的基本流程 2) 双亲委派模型 3. JVM 中垃圾回收机制 1) 找到垃圾 a) 引用计数 b) 可达性分析 2) 释放垃圾 1. JVM 内存区域划分 一个运行起来的 Java 进程&#xff0c;其实就是一个 JVM 虚拟机。 而进程是…

微信小程序跳转其他小程序以及跳转网站

一、跳转其他小程序 1.1 知道appid和页面路径 wx.navigateToMiniProgram({appId: appid, // 替换为目标小程序 AppIDpath: pathWithParams, // 小程序路径envVersion: release, // 开发版、体验版或正式版success(res) {console.log("跳转到其他小程序成功&#xff01;&q…

学习笔记:从ncsi/nc-si协议和代码了解网络协议的设计范式

学习笔记&#xff1a;从ncsi/nc-si协议和代码了解网络协议的设计范式 参考文档&#xff1a; https://www.dmtf.org/standards/published_documents https://www.dmtf.org/dsp/DSP0222 https://www.dmtf.org/sites/default/files/standards/documents/DSP0222_1.2.0.pdf参考代…

深度学习训练参数之学习率介绍

学习率 1. 什么是学习率 学习率是训练神经网络的重要超参数之一&#xff0c;它代表在每一次迭代中梯度向损失函数最优解移动的步长&#xff0c;通常用 η \eta η 表示。它的大小决定网络学习速度的快慢。在网络训练过程中&#xff0c;模型通过样本数据给出预测值&#xff0…

【数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 测试说明 我的通关代码: 测试结果&#xff1a; 任务描述 本关任务&#xff1a;编写一个程序实现单链表的基本运算。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;初始化线性表、销毁线性表、判定是否为空表、求线性…

利用ROS的Camera Calibration工具进行D435相机标定

一、安装ROS Camera Calibration sudo apt-get install ros-melodic-camera-calibration 二、安装realsense-ros 安装ROS Wrapper for Intel RealSense&#xff08;realsense-ros&#xff09; 三、启动数据读取节点 ctrlaltt打开终端 cd catkin_ws_ur source devel/setu…

让文案生成更具灵活性/chatGPT新功能canvas画布编辑

​ ​ OpenAI最近在2024年12月发布了canvas画布编辑功能&#xff0c;这是一项用途广泛的创新工具&#xff0c;专为需要高效创作文案的用户设计。 无论是职场人士、学生还是创作者&#xff0c;这项功能都能帮助快速生成、优化和编辑文案&#xff0c;提升效率的同时提高内容质量…

C# 网络编程--关于UDP 通信(二)

UDP (User Datagram Protocol) 是一种无连接的传输层协议&#xff0c;主要用于支持数据报文的传输。它的主要特点包括简单、高效、不保证可靠性和顺序。 1.UDP协议基本概念 1.udp基于IP的简单的协议&#xff0c;不可靠的协议 2.优点&#xff1a;简单、 轻量化、 传输速度高、…

Spring Boot 集成 MyBatis 全面讲解

Spring Boot 集成 MyBatis 全面讲解 MyBatis 是一款优秀的持久层框架&#xff0c;与 Spring Boot 集成后可以大大简化开发流程。本文将全面讲解如何在 Spring Boot 中集成 MyBatis&#xff0c;包括环境配置、基础操作、高级功能和最佳实践。 一、MyBatis 简介 1. SqlSession …

解决Jmeter HTTP Cookie管理器cookie不生效

解决Jmeter HTTP Cookie管理器cookie不生效问题 解决Jmeter HTTP Cookie管理器cookie不生效问题1、设置Jmeter HTTP Cookie管理器cookie后&#xff0c;发起的请求显示[no cookies]jmeter问题复现&#xff1a;这里同样使用postman进行重试&#xff0c;发现是可以正常获取数据的&…

freeswitch(开启支持MCU视频会议,使用mod_av模块)

亲测版本centos 7.9系统–》 freeswitch1.10.9 本人freeswitch安装路径(根据自己的路径进入) /usr/local/freeswitch/etc/freeswitch场景说明: 有些场景想使用视频会议MCU融合画面进行开会使用方法: 第一步:下载插件 yum install -y epel-release yum install

IntelliJ IDEA 使用技巧与插件推荐

目录 常用使用技巧 1. 使用快捷键提升开发效率 2. 多光标编辑 3. 代码自动补全 4. 使用 Find Action 快速执行操作 5. 集成版本控制系统&#xff08;VCS&#xff09; 6. 快速查看代码文档 推荐插件 1. Lombok Plugin 2. Rainbow Brackets 3. Key Promoter X 4. Chec…

Centos7环境下安装Flink1.20

目录 介绍1、涉及安装包2、节点3、修改hostname4、将flink安装包上传并解压5、修改配置文件6、修改masters和workers&#xff08;所有节点&#xff09;7、集群启停 介绍 Flink 是一个分布式系统&#xff0c;需要有效分配和管理计算资源才能执行流应用程序。它集成了所有常见的…

CTFHub 技能树 Web RCE eval执行(学习记录)

eval执行 源代码 <?php if (isset($_REQUEST[cmd])) {eval($_REQUEST["cmd"]); } else {highlight_file(__FILE__); } ?> PHP代码显示&#xff0c;要求将命令赋值给cmd然后执行 先查看一下根目录文件 /?cmdsystem("ls"); 查看上一级目录找flag文…

人员离岗监测摄像机智能人员睡岗、逃岗监测 Python 语言结合 OpenCV

在安全生产领域&#xff0c;人员的在岗状态直接关系到生产流程的顺利进行和工作环境的安全稳定。人员离岗监测摄像机的出现&#xff0c;为智能人员睡岗、逃岗监测提供了高效精准的解决方案&#xff0c;而其中的核心技术如AI识别睡岗脱岗以及相关的算法盒子和常见的安全生产AI算…