【力扣】146. LRU缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得关键字 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得关键字 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lru-cache
class LRUCache {
//LRU 缓存机制可以通过哈希表辅以双向链表实现,我们用一个哈希表和一个双向链表维护所有在缓存中的键值对。
private static class Node{
private int key;
private int value;
private Node prev; //前置结点
private Node next; //下一个节点
public Node(){}
public Node(int key,int value){
this.key = key;
this.value = value;
}
}
//当容量满的时候,采用LRU淘汰策略
//1.淘汰最少使用的数据
//2.淘汰最早放进来的数据
private Map<Integer,Node> map = new HashMap<Integer,Node>();
//标识容量 是一个固定值
private int capacity;
//标识大小,当前大小
private int size;
//头结点
private Node head;
//尾节点
private Node tail;
public LRUCache(int capacity) {
this.capacity = capacity;
this.size = 0;
// 使用伪头部和伪尾部节点
head = new Node();
tail = new Node();
head.next = tail;
tail.prev = head;
}
//如果 key 不存在,则返回 -1−1;
//如果 key 存在,则 key 对应的节点是最近被使用的节点。通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部,最后返回该节点的值
public int get(int key) {
Node result = map.get(key);
if(result == null){
return -1;
}
//通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部
result.prev.next = result.next;
result.next.prev = result.prev;
//把当前节点放到头结点
result.prev = head;
result.next = head.next;
head.next.prev = result;
head.next = result;
return result.value;
}
/**
对于 put 操作,首先判断 key 是否存在:
如果 key 不存在,使用 key 和 value 创建一个新的节点,在双向链表的头部添加该节点,并将 key 和该节点添加进哈希表中。然后判断双向链表的节点数是否超出容量,如果超出容量,则删除双向链表的尾部节点,并删除哈希表中对应的项;
如果 key 存在,则与 get 操作类似,先通过哈希表定位,再将对应的节点的值更新为 value,并将该节点移到双向链表的头部。
**/
public void put(int key, int value) {
Node result = map.get(key);
//若是没有则放入新的node节点
if(result == null){
Node node = new Node(key,value);
//添加到hash表
map.put(key,node);
//把新加入的节点放到链表的头部
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
++size;
//如果当前大小已经超出了容量,就把最久未使用的删除
if(size > capacity){
//去除hash表中的值
map.remove(tail.prev.key);
//去除链表中最久未使用的节点
tail.prev.prev.next = tail;
tail.prev = tail.prev.prev;
--size;
}
} else {
//若是有值,需要把原来的值覆盖
result.value = value;
map.put(key,result);
//把链表中的节点放到头结点
//先把当前节点删除
result.prev.next = result.next;
result.next.prev = result.prev;
//把当前节点放到头结点
result.prev = head;
result.next = head.next;
head.next.prev = result;
head.next = result;
}
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
【力扣】146. LRU缓存机制的更多相关文章
- 力扣 - 146. LRU缓存机制
目录 题目 思路 代码 复杂度分析 题目 146. LRU缓存机制 思路 利用双链表和HashMap来解题 看到链表题目,我们可以使用头尾结点可以更好进行链表操作和边界判断等 还需要使用size变量来 ...
- 【golang必备算法】 Letecode 146. LRU 缓存机制
力扣链接:146. LRU 缓存机制 思路:哈希表 + 双向链表 为什么必须要用双向链表? 因为我们需要删除操作.删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持 ...
- Java实现 LeetCode 146 LRU缓存机制
146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...
- 146. LRU 缓存机制 + 哈希表 + 自定义双向链表
146. LRU 缓存机制 LeetCode-146 题目描述 题解分析 java代码 package com.walegarrett.interview; /** * @Author WaleGar ...
- [Leetcode]146.LRU缓存机制
Leetcode难题,题目为: 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key ...
- 146. LRU缓存机制
题目描述 运用你所掌握的数据结构,设计和实现一个LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (key ...
- leetcode:146. LRU缓存机制
题目描述: 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 ( ...
- LeetCode 146. LRU缓存机制(LRU Cache)
题目描述 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (k ...
- Leetcode 146. LRU 缓存机制
前言 缓存是一种提高数据读取性能的技术,在计算机中cpu和主内存之间读取数据存在差异,CPU和主内存之间有CPU缓存,而且在内存和硬盘有内存缓存.当主存容量远大于CPU缓存,或磁盘容量远大于主存时,哪 ...
随机推荐
- sqlalchemy insert on duplicate update
sqlalchemy insert on duplicate update from sqlalchemy.dialects.mysql import insert insert_stmt = ins ...
- Part 28 AngularJS default route
At the moment the problem is that, if you try to navigate to a route that is not configured, you wil ...
- OAuth 2.0 扩展协议之 PKCE
前言 阅读本文前需要了解 OAuth 2.0 授权协议的相关内容, 可以参考我的上一篇文章 OAuth 2.0 的探险之旅. PKCE 全称是 Proof Key for Code Exchange, ...
- 『学了就忘』Linux软件包管理 — 45、yum源文件详细说明
目录 1.yum源文件解析 2.查看yum源文件 3.搭建本地光盘yum源 第一步: 第二步: 第三步: 提示:RPM包的在线安装就是yum安装,yum安装需要依据yum源文件内容配置来寻找软件.本文 ...
- Nginx server_name翻译
http://nginx.org/en/docs/http/server_names.html#regex_names 匹配优先顺序 精确名称,无通配符,无正则. 以星号开头的最长的通配符名称,例如& ...
- [bzoj3038]上帝造题的7分钟2
考虑每一个位置最多开6次左右就会变成1,然后操作就没有意义了,因此对线段树维护区间和和一个标记,表示是否全部都是1,然后对于修改,如果区间标记不是1就暴力下去,是1就不用操作,复杂度为$o(6nlog ...
- [luogu6860]象棋与马
根据扩欧$(a,b)=1$必须要满足,同时,若$a+b$为偶数则格子的"奇偶性"不变,因此$a+b$必须为奇数 反过来,容易证明满足$(a,b)=1$且$a+b$为奇数则一定可行( ...
- Python学习手册——第二部分 类型和运算(1)之字符串
Python全景 1.程序由模块构成. 2.模块包含语句. 3.语句包含表达式. 4.表达式建立并处理对象. 在python中数据是以对象的形式出现的!!! 为什么使用内置类型 内置对象使程序更容易编 ...
- jpa生成uuid
使用jpa可以生成uuid,但是我直接添加数据没有id值会报错,只在程序中有效,如果直接修改数据库需要手动填写,另外长度不要乱填 ,之前填了200,找了半天才找到原因. package com.jav ...
- 基于Docker搭建Maven私服Nexus,Nexus详解
备注:首先在linux环境安装Java环境和Docker,私服需要的服务器性能和硬盘存储要高一点,内存不足可能到时启动失败,这里以4核8GLinux服务器做演示 一:基于Docker安装nexus3 ...