【LeetCode-中等题】146. LRU 缓存

news2025/5/21 15:11:55

文章目录

    • 题目
    • 方法一:直接继承LinkedHashMap调用api
    • 方法二:自定义LinkedHashMap = HashMap + ListNode == LinkedHashMap

题目

LRU缓存是什么:LRU缓存机制,你想知道的这里都有
实现 LRU 缓存算法
在这里插入图片描述

方法一:直接继承LinkedHashMap调用api

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

方法二:自定义LinkedHashMap = HashMap + ListNode == LinkedHashMap

map —>key存 integer value存链表节点
ListNode 存 next 和prev 引用 以及 存 key 和value 具体值

步骤:

  1. 定义一个自定义的双向链表节点类 DLinkedNode,该类包含 key 和 value 字段,并且具有 prev 和 next 指针用于构建双向链表。
  2. 创建一个哈希表 cache 用于存储键值对,其中键为索引,值为双向链表的节点。
  3. 定义变量 size 表示当前哈希表中已存储的键值对数量。
  4. 定义变量 capacity 表示哈希表的容量。
  5. 创建伪头部节点 head 和伪尾部节点 tail,并将它们连接起来形成一个空的双向链表。

方法列表:

  1. 构造函数 LRUCache(int capacity):初始化缓存的容量,同时初始化 size、capacity、head 和 tail 变量。
  2. int get(int key):获取指定键对应的值,如果键不存在则返回 -1。如果键存在,则通过哈希表定位到双向链表中的节点,并将该节点移到链表头部,然后返回节点的值。
  3. void put(int key, int value):插入或更新键值对。如果键已存在,则更新对应的值,并将对应的节点移到链表头部。如果键不存在,则创建一个新的节点,添加到哈希表和链表头部。如果插入后超出容量,则删除尾部节点,并从哈希表中移除对应的记录。
  4. DLinkedNode removeTail():在超出容量时删除尾部节点,并返回删除的尾部节点。
  5. void addToHead(DLinkedNode newNode):将指定节点添加到伪头部节点的后面。
  6. void moveToHead(DLinkedNode node):将指定节点移到伪头部节点的后面,即删除原位置的节点并将其添加到伪头部节点后面。
  7. void removeNode(DLinkedNode node):从双向链表中删除指定节点。
class LRUCache {
    /**
     * 自定义双向链表
     */
    class DLinkedNode {
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;
        public DLinkedNode() {}
        public DLinkedNode(int _key, int _value) {key = _key; value = _value;}
    }

    private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();//定义哈希表  key为索引  value为双向链表的节点
    private int size;//map的存值后的大小
    private int capacity;//map 的容量
    private DLinkedNode head, tail; //定义双向链表的伪头部和伪尾部节点



    /**
     * 定义初始容量方法
     * @param capacity
     */
    public LRUCache(int capacity) { //定义初始容量方法
        this.size = 0;
        this.capacity = capacity;
        // 使用伪头部和伪尾部节点
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;

    }

    /**
     * 依据key获取对应value
     * @param key
     * @return
     */
    public int get(int key) {
        DLinkedNode node = cache.get(key);//获取key对应的链表节点
        if (node == null) {  //如果node为null  说明key没有对应的value值
            return  -1;
        }
        // 如果 key 存在,先通过哈希表定位,再移到头部
        moveToHead(node);//将待get的节点移动到头部,再返回节点的值
        return node.value;
    }

    /**
     * 往哈希表中添加元素的方法
     * @param key
     * @param value
     */
    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);//put时  先获取这个key的位置有没有值  有?覆盖原值  没有就插入进去
        if (node == null) {// 如果 key 不存在,创建一个新的节点
            DLinkedNode newNode = new DLinkedNode(key, value);
            // 添加进哈希表
            cache.put(key, newNode);
            // 添加至双向链表的头部
            addToHead(newNode);
            size++; //map集合元素+1
            if (size > capacity) {
                // 如果超出容量,删除双向链表的尾部节点
                DLinkedNode tail = removeTail(); //从链表中把尾结点删除,并且方法得返回这个节点  方便map把这个节点对应的元素remove掉
                cache.remove(tail.key);
                size--;
            }
        }else{// 如果 key 存在,覆盖原值,并移到链表头部
            node.value = value;
            moveToHead(node);
        }
    }

    /**
     * 超出容量时删除尾部节点 并且返回尾部节点  方便对清除map中的残留
     * @return
     */
    private DLinkedNode removeTail() {
        DLinkedNode tailNode = tail.prev;//获取伪尾节点的前一个节点  即链表真实的尾节点
        removeNode(tailNode);
        return tailNode;//返回尾部节点  方便对清除map中的残留
    }


    /**
     * 新增节点时节点添加到伪头结点后面的位置
     * @param newNode
     */
    private void addToHead(DLinkedNode newNode) {
        newNode.prev = head;
        newNode.next = head.next;
        head.next.prev = newNode;
        head.next = newNode;
    }

    /**
     * get方法获取key对应value
     * put方法出现重复key时  覆盖原value
     * 这两种情况都会触发将操作的节点移动到伪首节点的后面
     * @param node
     */
    private void moveToHead(DLinkedNode node) {
        //删除原位置的自己
        removeNode(node);
        //将自己添加到伪首节点的后面
        addToHead(node);//调用上面写过的将节点添加到伪首节点的后面
    }

    /**
     * 删除node节点
     * @param node
     */
    private void removeNode(DLinkedNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
        node.next = null;
        node.prev = null;
    }

}

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

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

相关文章

深度图相关评测网站

文章目录 1 单目/Stereo相关测评网站介绍12 单目/Stereo相关测评网站介绍23 单目/Stereo相关测评网站介绍3 1 单目/Stereo相关测评网站介绍1 https://vision.middlebury.edu/stereo/eval3/ 2 单目/Stereo相关测评网站介绍2 http://www.cvlibs.net/datasets/kitti/eval_stereo…

Vscode画流程图

1.下载插件 Draw.id Integration 2.桌面新建文件&#xff0c;后缀名改为XXX.drawio 在vscode打开此文件 &#xff0c;就可以进行绘制流程图啦

无涯教程-Android - Broadcast Receivers

Broadcast Receivers 仅响应来自其他应用程序或系统本身的广播消息&#xff0c;这些消息有时称为events或intents。例如&#xff0c;应用程序还可以启动广播&#xff0c;以使其他应用程序知道某些数据已下载到设备并可供他们使用&#xff0c;因此广播接收器将拦截此通信并启动适…

做区块链卡牌游戏有什么好处?

区块链卡牌游戏是一种基于区块链技术的创新性游戏形式&#xff0c;它将传统的卡牌游戏与区块链技术相结合&#xff0c;实现了去中心化、数字化资产的交易和收集。这种新型游戏形式正逐渐在游戏行业引起了广泛的关注和热潮。本文将深入探讨区块链卡牌游戏的定义、特点以及其在未…

自定义node-red节点中,如何编写节点的配置信息弹窗

前言 最近有读者通过博客向我咨询,在自定义node-red节点时,如何编写该节点的配置页面,就是我们通常见到的,双节节点打开的信息弹窗。如下图: 上面两张图,展示了inject节点与mqtt in 节点的配置弹窗。 在弹窗中,除了上面的删除,取消,完成,和下面的失效按钮。 中间…

以“迅”防“汛”!5G视频快线筑牢防汛“安全堤”

近期&#xff0c;西安多地突发山洪泥石流灾害。防洪救灾刻不容缓&#xff0c;为进一步做好防汛工作&#xff0c;加强防洪调度监管&#xff0c;切实保障群众的生命财产安全&#xff0c;当地政府管理部门亟需拓展智能化技术&#xff0c;通过人防技防双保障提升防灾救灾应急处置能…

模型的保存加载、模型微调、GPU使用及Pytorch常见报错

序列化与反序列化 序列化就是说内存中的某一个对象保存到硬盘当中&#xff0c;以二进制序列的形式存储下来&#xff0c;这就是一个序列化的过程。 而反序列化&#xff0c;就是将硬盘中存储的二进制的数&#xff0c;反序列化到内存当中&#xff0c;得到一个相应的对象&#xff…

深度学习论文: Segment Any Anomaly without Training via Hybrid Prompt Regularization

深度学习论文: Segment Any Anomaly without Training via Hybrid Prompt Regularization Segment Any Anomaly without Training via Hybrid Prompt Regularization PDF: https://arxiv.org/pdf/2305.10724.pdf PyTorch代码: https://github.com/shanglianlm0525/CvPytorch Py…

【计算机系统概论Yale.patt】第二章

文章目录 2.数据的表示与计算2.1 bit2.1.1 信号的编码表示2.1.2 计算机采用二进制的原因2.1.3 数据类型无符号整数有符号整数原码反码补码编码方式与范围移码4-bit的不同编码方式 2.1.4 IEEE754浮点数尾数指数0000 0000 含义1111 1111含义 例 2.2 进制转换2.2.1 二转十2.2.2 十…

python面试:使用cProfile剖析程序性能

我们需要安装tuna&#xff1a;pip install tuna 程序执行完毕后&#xff0c;我们会得到一个results.prof&#xff0c;在CMD中输入指令&#xff1a;“tuna results.prof”。 import time import cProfile import pstatsdef add(x, y):resulting_sum 0resulting_sum xresulti…

mysql数据表Table is marked as crashed and should be repaired 的解决办法

错误原因 网上查了一下&#xff0c;错误的产生原因&#xff0c;有网友说是频繁查询和更新XXXX表造成的索引错误&#xff0c;还有说法是Mysql数据库因某种原因而受到了损坏。 【如&#xff1a;数据库服务器突发性断电&#xff0c;在数据表提供服务时对表的源文件进行某种操作都…

Java程序生成可执行exe文件及可安装程序

Java程序生成可执行exe文件及可安装程序 文章目录 Java程序生成可执行exe文件及可安装程序整体流程Maven项目打成jar包打成可执行文件准备工作&#xff1a;exe4j的下载、安装与激活使用exe4j打包 打成可安装文件参考 整体流程 将项目打包成可正常运行的jar包&#xff08;使用命…

涉及结构体的排序问题

简单举一个例子来介绍涉及结构体的排序问题。 例&#xff1a;输入若干学生姓名、语文成绩、数学成绩、英语成绩&#xff0c;根据三科成绩总分由高到低进行排序。 输入数据&#xff1a; 小明 78 89 90 小红 87 88 77 小华 91 92 96 输出样例&#xff1a; 小华 91 92 96 279 小明…

通义千问本地化部署不调用GPU只调用CPU的检查方法

今天部署本地版通义千问的时候遇到一个问题。 启动他的cli_demo.py调用的一直都是CPU模式的。 检查cuda已经正确安装&#xff0c;后面发现是torch即PyTorch的安装问题。 我安装torch的时候&#xff0c;用的是默认指令&#xff0c;没有增加别的参数。 检测一下&#xff0c;输出…

正中优配:创业板指大涨3.47%!减速器等概念板块掀涨停潮!

周二&#xff08;8月29日)&#xff0c;三大股指团体涨超1%。截至上午收盘&#xff0c;上证指数涨1.39%&#xff0c;报3141.82点&#xff1b;深证成指和创业板指别离涨2.41%和3.47%&#xff1b;沪深两市算计成交额6264.51亿元&#xff0c;总体来看&#xff0c;两市个股涨多跌少&…

教会你怎么玩转 文件下载

&#x1f600;前言 教会你怎么玩转 文件下载 &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我的动力&#x1f609;&#x1f609; 在csdn获奖荣誉: …

使用apifox前置数据base64编码并添加一个字段

具体前置脚本如下&#xff1a; // pm.request.body.update 处理 body 参数里的变量 let bodyStr pm.request.body.raw; // base64 编码数据 let bodyEncode btoa(bodyStr); console.log(bodyEncode) let newBody {"data": bodyEncode,"sendTime": &qu…

MySQL8.xx 解决1251 client does not support ..解决方案

MySQL8.0.30一主两从复制与配置(一)_蜗牛杨哥的博客-CSDN博客 MySQL8.xx一主两从复制安装与配置 MySQL8.XX随未生成随机密码解决方案 一、客户端连接mysql&#xff0c;问题&#xff1a;1251 client does not support ... 二、解决 1.查看用户信息 备注&#xff1a;host为 % …

智慧水产养殖方案,守护养殖水产品安全!

水产品在人们的饮食文化中占据着举足轻重的地位&#xff0c;更是人们摄入蛋白质的重要来源。因此&#xff0c;保障食品安全&#xff0c;提升养殖水产品的品质至关重要然。而传统的人工观察水产养殖方式较为单一&#xff0c;难以及时发现水质问题和投喂情况&#xff0c;容易导致…

Springboot2.0快速入门(第一章)

目录 一&#xff0c;SpringBoot简介1.1&#xff0c;回顾什么是Spring1.2&#xff0c;Spring是如何简化Java开发的1.3&#xff0c;什么是SpringBoot 二&#xff0c;Hello&#xff0c;World2.1&#xff0c;准备工作2.2&#xff0c;创建基础项目说明2.3&#xff0c;创建第一个Hell…