Java算法_ LRU 缓存(LeetCode_Hot100)

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

获得更多?算法思路:代码文档,算法解析的私得。

运行效果
在这里插入图片描述

完整代码

import java.util.HashMap;
import java.util.Map;

/**
 * 2 * @Author: LJJ
 * 3 * @Date: 2023/8/7 13:14
 * 4
 */
public class LRUCache {
    class Node{
        int key;
        String value;
        Node prev;
        Node next;

        public Node(int key , String value){
            this.key = key;
            this.value = value;
        }
    }

    private int capacity;
    private Map<Integer,Node> cache;
    private Node head;
    private Node tail;

    // 初始化LRUCache类的构造函数,
    // 使用了一个哨兵节点的技巧,将head和tail初始化为哨兵节点,并不存储具体的键值对。
    // 哨兵节点可以简化链表的操作,避免处理头部和尾部节点时需要特殊处理的情况。
    public LRUCache(int capacity){
        this.capacity = capacity;
        cache = new HashMap<>();
        //初始化头尾节点;
        head = new Node(-1, "-1");
        tail = new Node(-1, "-1");
        head.next = tail;
        tail.prev = head;
    }

    public String get(int key){
       if (cache.containsKey(key)){
            Node node = cache.get(key);
            //将查到的节点移动到链表头部
            removeNode(node);
            addToHead(node);
            return node.value;
        }
        return "-1";
    }

    public void put(int key, String value){
        if (cache.containsKey(key)){
            Node node = cache.get(key);
            node.value = value;
            //将更新后的节点移动到链表头部
            removeNode(node);
            addToHead(node);
        }else {
            if (cache.size() >= capacity){

                //如果缓存已满,需要移除最久未使用的节点(即链表尾部节点)
                cache.remove(tail.prev.key);
                removeNode(tail.prev);
            }
            Node newNode = new Node(key,value);
            cache.put(key,newNode);
            //将新的节点插入链表头部
            addToHead(newNode);
        }
    }

    // 将节点插入链表头部
    private void addToHead(Node node){
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
        node.prev = head;
    }

    //移除节点
    private void removeNode(Node node){
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private static void printCache(Node head){
        Node current = head;
        while (current != null){
            System.out.print("(" + current.key + ", " + current.value + ") -> ");
            current = current.next;
        }
        System.out.println("null");
    }
    public static void main(String[] args) {
        LRUCache lruCache = new LRUCache(3);

        // 插入键值对 (1, "A")
        lruCache.put(1, "A");
        // 插入键值对 (2, "B")
        lruCache.put(2, "B");
        // 插入键值对 (3, "C")
        lruCache.put(3, "C");

        // 此时缓存状态为:3 -> 2 -> 1,其中1是最近访问的,3是最久未使用的
        System.out.println("初始缓存状态为:");
        printCache(lruCache.head);
        // 获取键1对应的值,输出"A"
        System.out.println(" // 获取键1对应的值:"+lruCache.get(1));

        // 此时缓存状态不变:1 -> 3 -> 2
        System.out.println("获取键1对应的值,输出\"A\"后的缓存状态为:");
        printCache(lruCache.head);
        // 插入键值对 (4, "D"),此时缓存已满,需要逐出最久未使用的键值对,即键2 -> 值B被逐出
        lruCache.put(4, "D");

        // 此时缓存状态为:4 -> 1 -> 3,其中3是最久未使用的,4是最近访问的
        System.out.println("插入键值对 (4, \"D\"),此时缓存已满,需要逐出最久未使用的键值对,即键2 -> 值B被逐出的缓存状态为:");
        printCache(lruCache.head);
        // 获取键2对应的值,由于键2已经被逐出,输出-1
        System.out.println("获取键2对应的值:"+lruCache.get(2));

        // 此时缓存状态不变:4 -> 1 -> 3
        System.out.println("获取键2对应的值,由于键2已经被逐出,输出-1的缓存状态为:");
        printCache(lruCache.head);
        // 插入键值对 (5, "E"),此时缓存已满,需要逐出最久未使用的键值对,即键3 -> 值C被逐出
        lruCache.put(5, "E");

        // 此时缓存状态为:5 -> 4 -> 1,其中1是最久未使用的,5是最近访问的
        System.out.println("插入键值对 (5, \"E\"),此时缓存已满,需要逐出最久未使用的键值对,即键3 -> 值C被逐出的缓存状态为:");
        printCache(lruCache.head);
        // 获取键3对应的值,由于键3已经被逐出,输出-1
        System.out.println("获取键3对应的值:"+lruCache.get(3));

        // 此时缓存状态不变:5 -> 4 -> 1
        System.out.println(" // 获取键3对应的值,由于键3已经被逐出,输出-1的缓存状态为:");
        printCache(lruCache.head);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序备案流程

微信小程序备案流程 &#x1f4d4; 千寻简笔记介绍 千寻简笔记已开源&#xff0c;Gitee与GitHub搜索chihiro-notes&#xff0c;包含笔记源文件.md&#xff0c;以及PDF版本方便阅读&#xff0c;且是用了精美主题&#xff0c;阅读体验更佳&#xff0c;如果文章对你有帮助请帮我…

Oracle database Linux自建环境备份至远端服务器自定义保留天数

环境准备 linux下安装oracle 请看 oracle12c单节点部署 系统版本: CentOS 7 软件版本&#xff1a; Oracle12c 备份策略与实现方法 此次备份依赖Oracle自带命令exp与linux下crontab命令&#xff08;定时任务&#xff09; exp Oracle中exp命令是一个用于导出数据库数据和对象的…

算法竞赛入门【码蹄集新手村600题】(MT1140-1160)C语言

算法竞赛入门【码蹄集新手村600题】(MT1140-1160&#xff09;C语言 目录MT1141 数字3MT1142 整除的总数MT1143 沙哈德数MT1144 整除MT1145 全部整除MT1146 孙子歌诀MT1147 古人的剩余定理MT1148 隐晦余8MT1149 余数MT1150 战死四五百MT1151 韩信生气MT1152 韩信又生气了MT1153 …

UML类图

UML类图 类与类之间的关系 类与类之间的关系 依赖 一个类的对象,作为另一个类的局部变量, 虚线加箭头表示继承 实线三角实现 虚线三角关联 一个类的对象,作为一个类的字段 实线箭头 a. 组合 实心菱形实线箭头 b. 聚合 空心菱形实线箭头

甄品焕新|燕千云服务请求预警功能上线,燕小千AIGC能力再升级

​ 燕千云数智化业务服务平台发布了1.23.0版本&#xff0c;此次版本上线了服务请求预警功能&#xff0c;增加呼叫中心服务场景中的通话质检功能&#xff0c;提高了企业IT服务效率。此次还升级了燕小千AIGC能力&#xff0c;不仅可以实时预估文档学习时间&#xff0c;还可以一键分…

MySQL 存储过程、函数、触发器、事件

​ 目录 存储过程 创建存储过程 调用存储过程 查看存储过程 删除存储过程 进阶 变量 if条件判断 传递参数 case结构 while循环 repeat结构 loop语句 leave语句 游标/光标 存储函数 触发器 创建触发器 删除触发器 查看触发器 事件 查看事件调度器是否开启…

Nginx负载均衡(重点)

正向代理 部署正向代理 server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; proxy_pass http://20.0.0.60:80…

新手如何快速学习单片机?

初步确定学习目标&#xff1a;是学习简单便宜的51呢&#xff0c;还是学习简单但是性价比已经不算太高的&#xff0c;但是功能强大稳定可靠的avr&#xff0c;还是物美价廉的stm32&#xff0c;或者ARM9&#xff08;可以跑系统了&#xff09;&#xff0c;再往上x86什么的如果是学8…

【Linux】UDP协议——传输层

目录 传输层 再谈端口号 端口号范围划分 认识知名端口号 两个问题 netstat与iostat pidof UDP协议 UDP协议格式 UDP协议的特点 面向数据报 UDP的缓冲区 UDP使用注意事项 基于UDP的应用层协议 传输层 在学习HTTP等应用层协议时&#xff0c;为了便于理解&#xff…

Word转PDF在线转换如何操作?分享转换技巧

现如今&#xff0c;pdf转换器已成为大家日常办公学习必不可少的工具&#xff0c;市场上的pdf转换器主要有两种类型&#xff0c;一种是需要下载安装的&#xff0c;另一种是网页版&#xff0c;打开就可以使用的&#xff0c;今天小编给大家推荐一个非常好用的网页版pdf转换器&…

json-server的入门

由于前端开发的时候&#xff0c;需要向后端请求数据&#xff0c;有的时候后端还没有准备好&#xff0c;所以需要使用一些简单的静态数据&#xff0c;但是我们更加希望能够模拟请求以及请求回来的过程&#xff0c;这个时候就需要使用json-server Json-Server的介绍 json-server…

bye 我的博客网站

Bye&#x1f64b;&#x1f64b;&#x1f64b;&#xff0c;我的博客网站。在我的服务器上运行了9个月之久的博客网站要和大家Bye了。 背景 可能很多人不知道我的这个博客网站的存在&#xff0c;好吧&#xff0c;最后一次展示它了&#xff0c;博客网站地址在这里&#xff0c;它…

【unity】ShaderGraph实现等高线和高程渐变设色

【unity】ShaderGraph实现等高线和高程渐变设色 等高线的实现思路 方法一&#xff1a; 通过Position节点得到顶点的高度&#xff08;y&#xff09;值&#xff0c;将高度值除去等高距离取余&#xff0c;设定余数的输出边界&#xff08;step&#xff09; 方法二&#xff1a; 将…

ElasticSearch详细操作

ElasticSearch搜索引擎详细操作以及概念 文章目录 ElasticSearch搜索引擎详细操作以及概念 1、_cat节点操作1.1、GET/_cat/nodes&#xff1a;查看所有节点1.2、GET/_cat/health&#xff1a;查看es健康状况1.3_、_GET/_cat/master&#xff1a;查看主节点1.4、GET/_cat/indices&a…

STM32F105RCT6 -- ST-Link ITM Trace printf 打印日志

1. STM32 可以配置UASRT&#xff0c;使用串口来打印日志&#xff0c;还有另外一种方式&#xff0c;使用ITM 调试功能来打印日志&#xff0c; 主要使用到的三个函数 core_cm3.h 1.1 发送函数 static __INLINE uint32_t ITM_SendChar(uint32_t ch)&#xff0c;相当于串口的发送函…

分享之python 协程

线程和进程的操作是由程序触发系统接口&#xff0c;最后的执行者是系统&#xff1b;协程的操作则是程序员。 协程存在的意义&#xff1a;对于多线程应用&#xff0c;CPU通过切片的方式来切换线程间的执行&#xff0c;线程切换时需要耗时&#xff08;保存状态&#xff0c;下次继…

CMU 15-445 -- Introduction to Distributed Databases - 19

CMU 15-445 -- Introduction to Distributed Databases - 19 引言System ArchitectureShared MemoryShared DiskShared Nothing Early Distributed Database SystemsDesign IssuesHomogeneous VS. Heterogeneous Database PartitioningNaive Table PartitioningHorizontal Part…

Grafana技术文档--基本安装-docker安装并挂载数据卷-《十分钟搭建》

阿丹&#xff1a; Prometheus技术文档--基本安装-docker安装并挂载数据卷-《十分钟搭建》_一单成的博客-CSDN博客 在正确安装了Prometheus之后开始使用并安装Grafana作为Prometheus的仪表盘。 一、拉取镜像 搜索可拉取版本 docker search Grafana拉取镜像 docker pull gra…

数字万用表测量基础知识--DMM的显示位数

概览 DMM&#xff08;即数字万用表&#xff09;是一种电气测试和测量仪器&#xff0c;可测量直流和交流信号的电压、电流和电阻。本文介绍如何正确使用和理解数字万用表(DMM)。 DMM的显示位数 数字万用表(DMM)可用于进行各种测量。在选择DMM或理解所使用的DMM时&#xff0c;首…

Lecoode有序数组的平方977

题目建议&#xff1a; 本题关键在于理解双指针思想 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a; 双指针法经典题目 | LeetCode&#xff1a;977.有序数组的平方_哔哩…