Leetcode 146. LRU 缓存机制
前言
缓存是一种提高数据读取性能的技术,在计算机中cpu和主内存之间读取数据存在差异,CPU和主内存之间有CPU缓存,而且在内存和硬盘有内存缓存。当主存容量远大于CPU缓存,或磁盘容量远大于主存时,哪些数据应该被应该被清理,哪些数据应该被保留,这就需要缓存淘汰策略来决定。常见的策略有三种:先进先出策略FIFO(First In,First Out)、最少使用策略LFU(Least Frequently Used)、最近最少使用策略LRU(Least Recently Used)。
LRU描述
设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
- LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
- int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
- void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
解题思路 哈希表 + 双向链表
- 针对LRU的特点,选择使用双链表实现。
- 使用 gut 方法获取数据,如果有数据,把返回数据,并且把数据放在链表头部。
- 使用 put 方法存放数据,如果数据存在,直接覆盖新值;如果数据不存在,添加新值。新值都放在链表头部。此外,还需要判断缓存有没有超出容量 capacity,如果有超出,删除链表的尾结点。
- 因为是单链表,每次获取数据,或者删除数据,都需要遍历一遍链表,时间复杂度是O(n),这里使用hash来记录每个数据的位置,将数据访问的时间复杂度降到O(1)。
class LRUCache {
class DLinkedNode{
int key;
int value;
DLinkedNode prev;
DLinkedNode next;
public DLinkedNode() {}
public DLinkedNode(int key, int value) {
this.key = key;
this.value = value;
}
}
private int size;
private int capacity;
private DLinkedNode head;
private DLinkedNode tail;
private Map<Integer,DLinkedNode> cache = new HashMap<>();
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
DLinkedNode node = cache.get(key);
if (node == null) {
return -1;
}
//找到并移动到首位
moveToHead(node);
return node.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);
size++;
if (size > capacity) {
//超出容量,移除最后节点
DLinkedNode tail = removeTail();
cache.remove(tail.key);
size--;
}
} else {
//key存在,覆盖value,并移到头部
if (node.value != value) {
node.value = value;
}
moveToHead(node);
}
}
private DLinkedNode removeTail() {
DLinkedNode node = tail.prev;
removeNode(node);
return node;
}
private DLinkedNode removeNode(DLinkedNode node) {
node.next.prev = node.prev;
node.prev.next = node.next;
return node;
}
private void moveToHead(DLinkedNode node) {
removeNode(node);
addToHead(node);
}
private void addToHead(DLinkedNode node) {
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
}
参考
LRU维基百科
极客时间-王争-如何实现LRU缓存淘汰算法?
Leetcode 146. LRU 缓存机制的更多相关文章
- Java实现 LeetCode 146 LRU缓存机制
146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...
- [Leetcode]146.LRU缓存机制
Leetcode难题,题目为: 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key ...
- LeetCode 146. LRU缓存机制(LRU Cache)
题目描述 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (k ...
- 力扣 - 146. LRU缓存机制
目录 题目 思路 代码 复杂度分析 题目 146. LRU缓存机制 思路 利用双链表和HashMap来解题 看到链表题目,我们可以使用头尾结点可以更好进行链表操作和边界判断等 还需要使用size变量来 ...
- 146. LRU 缓存机制 + 哈希表 + 自定义双向链表
146. LRU 缓存机制 LeetCode-146 题目描述 题解分析 java代码 package com.walegarrett.interview; /** * @Author WaleGar ...
- 【golang必备算法】 Letecode 146. LRU 缓存机制
力扣链接:146. LRU 缓存机制 思路:哈希表 + 双向链表 为什么必须要用双向链表? 因为我们需要删除操作.删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持 ...
- 【力扣】146. LRU缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果关键字 (key) ...
- leetcode:146. LRU缓存机制
题目描述: 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 ( ...
- 146. LRU缓存机制
题目描述 运用你所掌握的数据结构,设计和实现一个LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (key ...
随机推荐
- Python - 基础数据类型 dict 字典
字典简介 字典在 Python 里面是非常重要的数据类型,而且很常用 字典是以关键字(键)为索引,关键字(键)可以是任意不可变类型 字典由键和对应值成对组成,字典中所有的键值对放在 { } 中间,每一 ...
- react native踩坑记录
一 .安装 1.Python2 和Java SE Development Kit (JDK)可以直接通过腾讯电脑关键安装, Android SDK安装的时候路径里不能有中文和空格 2.配置java环境 ...
- xxe 回显与无回显
转载学习于红日安全 一.有回显 (1)直接将外部实体引用的URI设置为敏感目录 <!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY xxe ...
- Go通关04:正确使用 array、slice 和 map!
Array(数组) 数组存放的是固定长度.相同类型的数据. 数组声明 var <数组名> = [<长度>]<元素>{元素1,元素2} var arr = [2]in ...
- 简明易懂,将细节隐藏,面向新手树立web开发概念——学完Java基础语法,超快速上手springboot+mybatiJavaWeb开发
简明易懂,将细节隐藏,面向新手树立web开发概念 --学完Java基础语法,超快速上手JavaWeb开发 Web本质(先忽视各种协议) Web应用可以理解为浏览器和服务器之间的交互. 我们可以看一个简 ...
- 自学linux——16.LAMP项目上线流程
LAMP项目上线流程 一.编译安装与卸载Nginx(web服务器软件,类似于Apache) 1.安装nginx ① 下载nginx 网页下载https://nginx.org/en/downlo ...
- Cancer Cell | 肿瘤微环境渐进式调控AML治疗抵抗的分子机制
急性髓系白血病 ( acute myeloid leukemia, AML ) 是成年人常见的血液系统恶性肿瘤之一,主要表现为髓系原始细胞克隆性恶性增殖及正常造血细胞功能抑制.在AML基因突变图谱中, ...
- 阿里饿死了么Android面试凉经,两轮面完被虐哭了,怒清购物车。。。卸载饿死了么
大家应该看过很多分享面试成功的经验,但根据幸存者偏差的理论,也许多看看别人面试失败在哪里,对自己才更有帮助. 最近跟一个朋友聊天,他漫不经心地复习了几个月,就去参加了饿了么面试,第二面结束后,嗯,挂了 ...
- Java面板Panel的使用,监听窗口关闭事件
面板Panel的使用 待解决问题: 1.设计模式:适配器模式 2.frame.setLayout(null); package GUI; import javax.swing.*; import ja ...
- UVa11054 Gergovia的酒交易(数学归纳法)
直线上有\(n\)个等距村庄,每个村庄要么买酒,要么卖酒.设第\(i\)个村庄对酒的需求为\(A_i\)(\(-1000 \leqslant A_i \leqslant 1000\)),其中\(A_i ...