LeetCode刷题之HOT100之LRU缓存

2024-06-21 12:28

本文主要是介绍LeetCode刷题之HOT100之LRU缓存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2024/6/21 酷暑难耐,离开空调我将不知道能否《活着》,昨天跑步感觉全身的热无法排出去,出门那种热浪一阵一阵打过来,一点风都舍不得给我。早早的来到实验室,也没多早,九点哈哈,做题啦!

1、题目描述

在这里插入图片描述

2、逻辑分析

刚看到这个题目,我看了好久,看不懂啥意思,然后去看了题解以及代码,打算跳过这题的想法在脑海里飘过三四次,好长啊代码。但是我还是看完了,就是一个redis缓存思想。该算法使用了哈希表和双链表的数据结构。LRUCache 的大致思路是使用哈希表(如 HashMap)和双链表(Doubly Linked List)来实现一个最近最少使用(Least Recently Used, LRU)缓存机制。
具体思路如下:
数据结构:
使用 HashMap 来存储键值对(key-value pairs),其中 key 是缓存项的键,value 是对应的缓存值以及该值在双链表中的节点引用。
使用双链表来维护缓存项的访问顺序。最近访问的项位于链表的头部,而最久未访问的项位于链表的尾部
初始化:
创建一个空的双链表,包含头节点(head)和尾节点(tail),它们互相指向对方,形成一个循环链表。
初始化 HashMap 用于存储键值对。
get(key) 操作:
HashMap 中查找键(key)对应的节点。
如果节点存在(即该键在缓存中),则将该节点从当前位置删除,并重新插入到链表的头部,以表示该键最近被访问过。
返回该节点的值。
如果节点不存在,则返回 -1 表示未找到。
put(key, value) 操作:
HashMap 中查找键(key)对应的节点。
如果节点存在(即该键已经在缓存中),则更新该节点的值为新的 value,并将该节点从当前位置删除,重新插入到链表的头部。
如果节点不存在(即该键不在缓存中),则需要创建一个新节点,将新节点插入到链表的头部,并在 HashMap 中添加键值对。
如果此时缓存已满(即缓存中元素的数量超过了设定的容量),则需要删除链表尾部的节点,并在 HashMap 中移除对应的键值对,以腾出空间。
维护双链表:
当有新节点插入到链表的头部时,需要更新头节点和新节点的 prevnext 指针。
当有节点从链表中删除时,需要更新该节点的前一个节点和后一个节点的 prevnext 指针。
通过这种方式,LRU 缓存能够快速地访问最近使用过的数据,并在必要时淘汰最久未使用的数据,从而保持缓存的有效性。

3、代码演示

public class LRUCache {// 双链表节点类class DLinkedNode {int key;int value;DLinkedNode prev;DLinkedNode next;// 构造无参数的DLinkedNode实例(通常用于初始化头尾节点)public DLinkedNode(){}// 构造带有key和value的DLinkedNode实例public DLinkedNode(int _key, int _value){key = _key; value = _value;}}// 使用HashMap存储key到DLinkedNode的映射private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();// 当前缓存中元素的数量 private int size;// 缓存的最大容量private int capacity;// 双链表的头尾节点,用于维护最近最少使用(LRU)顺序private DLinkedNode head, tail;// 构造函数,初始化LRUCachepublic LRUCache(int capacity) {this.size = 0;this.capacity = capacity;// 初始化头尾节点,它们之间互相指向,构成一个空链表head = new DLinkedNode();tail = new DLinkedNode();head.next = tail;tail.prev = head;}// 根据key获取缓存值public int get(int key) {DLinkedNode node = cache.get(key);// 如果节点不存在,返回-1 if(node == null){return -1;}// 节点存在,将访问过的节点移动到头部moveToHead(node);// 返回节点的值return node.value;}// 将key-value对放入缓存public void put(int key, int value) {DLinkedNode node = cache.get(key);// 如果节点不存在,创建一个新的节点并放入缓存if(node == null){DLinkedNode newNode = new DLinkedNode(key, value);cache.put(key, newNode);// 将新节点添加到头部addToHead(newNode);// 缓存元素数量加1size++;// 如果超过容量,删除尾部的节点if(size > capacity){DLinkedNode tail = removeTail();// 从HashMap中移除该节点 cache.remove(tail.key);// 缓存元素数量减1size--;}// 如果节点已存在,更新节点的值并移动到头部}else{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;}
}

4、复杂度分析

  • 时间复杂度O(1)。get和put都只需要O(1)的时间。
  • 空间复杂度O(capacity)。capacity为最大缓存容量。

拜拜啦,我知道这题下次见到还是不能完整敲出来滴,那就希望下下次可以叭,再见!

这篇关于LeetCode刷题之HOT100之LRU缓存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1081223

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

Redis中使用布隆过滤器解决缓存穿透问题

一、缓存穿透(失效)问题 缓存穿透是指查询一个一定不存在的数据,由于缓存中没有命中,会去数据库中查询,而数据库中也没有该数据,并且每次查询都不会命中缓存,从而每次请求都直接打到了数据库上,这会给数据库带来巨大压力。 二、布隆过滤器原理 布隆过滤器(Bloom Filter)是一种空间效率很高的随机数据结构,它利用多个不同的哈希函数将一个元素映射到一个位数组中的多个位置,并将这些位置的值置

【每日刷题】Day113

【每日刷题】Day113 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 91. 解码方法 - 力扣(LeetCode) 2. LCR 098. 不同路径 - 力扣(LeetCode) 3. 63. 不同路径 II - 力扣(LeetCode) 1. 91. 解码方法 - 力扣(LeetCode) //思路:动态规划。 cl