leetcode146.手撸 LRU 算法(java)

news2024/11/15 17:22:12

LRU 缓存

  • LRU 缓存
    • 题目描述
    • LRU 介绍
    • LRU 算法设计
    • 代码实现
  • 单调栈算法

LRU 缓存

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/lru-cache

题目描述

请你设计并实现一个满足 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

LRU 介绍

LRU 缓存淘汰算法就是一种常用策略。LRU 的全称是 Least Recently Used,也就是说我们认为最近使用过的数据应该是是「有用的」,很久都没用过的数据应该是无用的,内存满了就优先删那些很久没用过的数据。

LRU 算法设计

leetcode 这道题就是让你设计一个数据结构,
首先要接收一个 capacity 参数作为缓存的最大容量,然后实现两个 API,一个是 put(key, val) 方法存入键值对,另一个是 get(key) 方法获取 key 对应的 val,如果 key 不存在则返回 -1。
get 和 put 方法必须都是 O(1) 的时间复杂度

设计要点:
要让 put 和 get 方法的时间复杂度为 O(1),我们可以总结出 cache 这个数据结构必要的条件:

1、显然 cache 中的元素必须有时序,以区分最近使用的和久未使用的数据,当容量满了之后要删除最久未使用的那个元素腾位置。
2、我们要在 cache 中快速找某个 key 是否已存在并得到对应的 val;
3、每次访问 cache 中的某个 key,需要将这个元素变为最近使用的,也就是说 cache 要支持在任意位置快速插入和删除元素
那么,什么数据结构同时符合上述条件呢?哈希表查找快,但是数据无固定顺序;链表有顺序之分,插入删除快,但是查找慢。所以结合一下,形成一种新的数据结构:哈希链表 LinkedHashMap。
LRU 缓存算法的核心数据结构就是哈希链表,双向链表和哈希表的结合体。这个数据结构长这样:
在这里插入图片描述

代码实现

class LRUCache {
    int cap;
    LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
    public LRUCache(int capacity) { 
        this.cap = capacity;
    }
    
    public int get(int key) {
        if (!cache.containsKey(key)) {
            return -1;
        }
        // 将 key 变为最近使用
        makeRecently(key);
        return cache.get(key);
    }
    
    public void put(int key, int val) {
        if (cache.containsKey(key)) {
            // 修改 key 的值
            cache.put(key, val);
            // 将 key 变为最近使用
            makeRecently(key);
            return;
        }
        
        if (cache.size() >= this.cap) {
            // 链表头部就是最久未使用的 key
            int oldestKey = cache.keySet().iterator().next();
            cache.remove(oldestKey);
        }
        // 将新的 key 添加链表尾部
        cache.put(key, val);
    }
    
    private void makeRecently(int key) {
        int val = cache.get(key);
        // 删除 key,重新插入到队尾
        cache.remove(key);
        cache.put(key, val);
    }
}

单调栈算法

leetcode84. 柱状图中最大的矩形

leetcode1856. 子数组最小乘积的最大值

单调栈的实现-单调递减栈和单调递增栈

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

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

相关文章

HNU-小学期工训-STC-B测试记录表

说明1“分类I”为检测电路板硬件测试案例&#xff0c;“分类ⅡI、Ⅲ、IV”为不同层次综合应用案例。"分类1、Ⅱ、Ⅲ”必做&#xff0c;“分类TV”选做。 说明2:“测试/故障现象记录”栏:记录实际测量效果并与案例说明对比&#xff0c;并记录;有故障时&#xff0c;记录所见…

《AutoSar实战》读写DID之一:CDD准备

文章目录 前言一、1.新建DID1&#xff0c;使用 **CANdelaStudio** 软件打开工程中的CDD文件并创建DID1) 创建DID2) 详细配置DID3&#xff09;配置读写服务权限 二、同步更新工具链配置1 更新文件并检查1&#xff09; 更新CDD文件2&#xff09;检查更新结果 总结 前言 本章节主…

大型语言模型与知识图谱协同研究综述:两大技术优势互补

机器之心报道 编辑&#xff1a;杜伟 多图综述理清当前研究现状&#xff0c;这篇 29 页的论文值得一读。 大型语言模型&#xff08;LLM&#xff09;已经很强了&#xff0c;但还可以更强。通过结合知识图谱&#xff0c;LLM 有望解决缺乏事实知识、幻觉和可解释性等诸多问题&am…

记录一下kibana启动连接报错问题(kibana server is not ready yet)

记录一下kibana启动连接报错问题(kibana server is not ready yet) 今天启动kibana出现该问题 先去看了看是否是elasticsearch连接出错 启动了容器 docker start elasticsearch docker start kibana进入了kibana容器 docker exec -it kibana bash进行了下面的操作&#xf…

注册微信小程序平台安装微信小程序开发工具(详细教程)

首先我们先去微信小程序平台注册账号&#xff0c;下面是网址 首页 | 微信开放社区 进入后&#xff0c;使用手机扫描登录&#xff0c;然后&#xff0c;选择小程序&#xff0c;选择个体——填写个人信息——进入到开发者平台&#xff08;相信这里对一个开发者很简单了吧&#xff…

API安全测试检查项小结

现如今开发基本上都是前后端分离&#xff0c;相比前端&#xff0c;后端的测试是最容易发现一些底层bug, 修复成本也低。今天主要聊聊接口的安全测试&#xff0c;以及常见的漏洞。 一、逻辑越权类 可以分为两类&#xff1a;平行越权&#xff1a;权限类型不变&#xff0c;权限对…

单线程JavaScript为何如此高效

什么是js执行机制 JavaScript 的执行机制指的是 JavaScript 代码在运行时的工作方式和顺序。它涉及以下几个关键概念&#xff1a; 单线程&#xff1a;JavaScript 是一门单线程的编程语言&#xff0c;意味着它只有一个主线程用于执行代码。这意味着 JavaScript 中的代码是按顺序…

编程(43)----------ConcurrentHashMap

在多线程中使用哈希表, 首先是不能使用HashMap的. 因为其本身并非线程安全. 与其相反HashTable则是安全的. 其原因在于本身给关键的方法加了锁. 但即便如此, 与HashTable相比, 更推荐使用ConcurrentHashMap. 其原因在于, 它在HashTable的基础上做了较多的优化: 上述提到, Hash…

自从前端用上了低代码,开发速度直接起飞

作为前端工作人员&#xff0c;我们都深知在这个快速发展的时代里&#xff0c;不断学习和掌握前沿技术是至关重要的。随着互联网的不断革新和新兴技术的崛起&#xff0c;我们需要保持敏锐的触角&#xff0c;紧跟潮流&#xff0c;才能在竞争激烈的市场中保持领先地位。 一直以来&…

MAC电脑垃圾好用的文件清理软件CleanMyMac X

古语云&#xff1a;“工欲善其事&#xff0c;必先利其器。”因此&#xff0c;一个运行流畅的Mac更能使我们的工作事半功倍。但又是什么导致电脑的运行不流畅呢&#xff1f; 其实这大多还是缓存垃圾过多、内存不足的原因。尝试安装了许多的垃圾文件清理软件&#xff0c;垃圾没有…

HashMap 为什么不能一边遍历一遍删除

前段时间&#xff0c;同事在代码中 KW 扫描的时候出现这样一条&#xff1a; 上面出现这样的原因是在使用 foreach 对 HashMap 进行遍历时&#xff0c;同时进行 put 赋值操作会有问题&#xff0c;异常 ConcurrentModificationException。 于是帮同简单的看了一下&#xff0c;印象…

为什么Qt成为工业软件开发的首选框架?

工业软件开发中使用Qt的主要原因有以下几点&#xff1a; 跨平台性&#xff1a;Qt是一个跨平台的C应用程序开发框架&#xff0c;可以在多个操作系统上运行&#xff0c;包括Windows、macOS、Linux等。这种跨平台性使得开发人员能够使用相同的代码库创建适用于不同操作系统的应用程…

Github-Readme-Stats 简明教程

注&#xff1a;本篇文章首发于 博客园sarexpine 为保持阅读的舒适性&#xff0c;可以选择移步至 博客园sarexpine 阅读&#xff0c;日后的文章将首发于 博客园sarexpine 平台&#xff0c;谢谢&#xff01; 1. 更新 Readme 文件 在你想要放置 Readme-WakaTime 的位置中放置以下…

Nginx【Nginx场景实践(动静分离、动静分离实战、缓存机制)】(十)-全面详解(学习总结---从入门到深化)

目录 Nginx场景实践_动静分离 Nginx场景实践_动静分离实战 Nginx场景实践_缓存机制 Nginx场景实践_动静分离 Nginx动静分离简单来说就是把动态和静态请求分开&#xff0c;不能理解成只是单纯的把动态页面和静态页面物理分离。严格意义上说应该是动态请求和静态请求分开&…

@Transaction事务导致的mysql连接耗尽源码分析

背景&#xff1a; Transaction注解是我们在日常的写代码过程中最常使用的事务注解了&#xff0c;本文就从spring源码的角度解析下这个注解的执行过程&#xff0c;以便分析为什么使用事务比正常的单sql执行更容易导致连接池耗尽 源码追踪&#xff1a; 本文假定使用PROPAGATIO…

音频怎么转文字?试试这三个简单的方法吧!

有时候我们会遇到一些比较重要的会议、讲座或者演讲&#xff0c;如果我们能够将这些声音记录下来&#xff0c;并将其转换为文字&#xff0c;就可以更加方便地保存和管理这些信息。这样&#xff0c;我们就不用再去听录音了&#xff0c;只需要看文字就可以了。此外&#xff0c;录…

智能指针的deleter机制

一、介绍 智能指针的deleter机制是指&#xff0c;当智能指针的引用计数降为0时&#xff0c;智能指针会自动调用一个指定的析构函数&#xff08;deleter&#xff09;来释放所管理的内存。这个析构函数通常是一个函数对象&#xff0c;可以是一个函数指针、一个lambda表达式或者一…

青少年机器人技术一级考试备考重点(四):功与能量以及常用传动装置

随着机器人技术的飞速发展&#xff0c;越来越多的青少年开始关注并参与其中。青少年机器人技术考试作为一项评估学生机器人技术水平的重要考试&#xff0c;备受广大青少年和家长的关注。为了更好地备战青少年机器人技术一级考试&#xff0c;了解考试的学习要点和备考重点是非常…

C++数据结构X篇_07_C++单向循环链表解决约瑟夫问题

本篇参考单向循环链表解决约瑟夫问题&#xff08;C&#xff09;整理&#xff0c;先搞懂结构框架&#xff0c;后期根据视频利用c对内容实现&#xff0c;也可以对c有更高的提升。 文章目录 1. 链表创建与初始化2. 添加插入、删除和打印函数3. 插入数据并核验4. 解决约瑟夫问题&am…

DM8:达梦数据库备份还原报错-文件已存在 -4558 file exists

DM8:达梦数据库备份还原报错-文件已存在 -4558 file exists 1 文件已存在 -4558 file exists2 使用 OVERWRITE 参数对数据库还原3 参数介绍 1 文件已存在 -4558 file exists 在数据库还原操作时&#xff0c;遇到报错文件已存在 -4558 file exists&#xff0c;可以使用OVERWRIT…