运用你所掌握的数据结构,设计和实现一个  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缓存机制的更多相关文章

  1. 力扣 - 146. LRU缓存机制

    目录 题目 思路 代码 复杂度分析 题目 146. LRU缓存机制 思路 利用双链表和HashMap来解题 看到链表题目,我们可以使用头尾结点可以更好进行链表操作和边界判断等 还需要使用size变量来 ...

  2. 【golang必备算法】 Letecode 146. LRU 缓存机制

    力扣链接:146. LRU 缓存机制 思路:哈希表 + 双向链表 为什么必须要用双向链表? 因为我们需要删除操作.删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持 ...

  3. Java实现 LeetCode 146 LRU缓存机制

    146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...

  4. 146. LRU 缓存机制 + 哈希表 + 自定义双向链表

    146. LRU 缓存机制 LeetCode-146 题目描述 题解分析 java代码 package com.walegarrett.interview; /** * @Author WaleGar ...

  5. [Leetcode]146.LRU缓存机制

    Leetcode难题,题目为: 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key ...

  6. 146. LRU缓存机制

    题目描述 运用你所掌握的数据结构,设计和实现一个LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (key ...

  7. leetcode:146. LRU缓存机制

    题目描述: 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 ( ...

  8. LeetCode 146. LRU缓存机制(LRU Cache)

    题目描述 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - 如果密钥 (k ...

  9. Leetcode 146. LRU 缓存机制

    前言 缓存是一种提高数据读取性能的技术,在计算机中cpu和主内存之间读取数据存在差异,CPU和主内存之间有CPU缓存,而且在内存和硬盘有内存缓存.当主存容量远大于CPU缓存,或磁盘容量远大于主存时,哪 ...

随机推荐

  1. tmux会话断电保存自动恢复

    tmux可以用于会话管理,通过建立session,可以保证当前设备和服务期断开连接之后,会话中的指令继续运行,非常适合用于执行需要长时间运行的任务. 但是tmux也有一个问题,那就是session在服 ...

  2. Beyond compare 4.2.3 激活和秘钥

    安装完 Beyond Compare 4.2.3 以后.打开输入密匙是不是会跳到官网去?不用慌,我们只需要删除你安装Beyond Compare 4目录下的 BCUnrar.dll 文件,然后再打开就 ...

  3. rabbitMQ报错:Caused by: com.rabbitmq.client.ShutdownSignalException: connection error; protocol method:

    1.输入的机器的 IP:15672进入Raabitmq的登陆管理界面 点击admin,进去点击set permission ok, 在运行应该就不会包这个错了

  4. SpringCloud升级之路2020.0.x版-34.验证重试配置正确性(3)

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们继续上一节针对我们的重试进行测试 验证针对可重试的方法响应超时异常重试正确 我们可以通 ...

  5. thinkphp5 目录结构

    /*    ├─application           应用目录    │  ├─common             公共模块目录(可以更改)    │  ├─module_name       ...

  6. python实现直线检测

    目录: (一)原理 (二)代码(标准霍夫线变换,统计概率霍夫线变换) (一)原理 1.霍夫变换(Hough Transform) 霍夫变换是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也 ...

  7. Netty源码分析之Reactor线程模型详解

    上一篇文章,分析了Netty服务端启动的初始化过程,今天我们来分析一下Netty中的Reactor线程模型 在分析源码之前,我们先分析,哪些地方用到了EventLoop? NioServerSocke ...

  8. [hdu6978]New Equipments II

    显然可以费用流来做,具体建图如下-- 点集:源点,汇点,左边$n$​个工人,右边$n$​​​个设备 边集:源点向第$i$​个工人连$(1,a_{i})$​的边,第$i$​个设备向汇点连$(1,b_{i ...

  9. mysql注入绕过information_schema过滤

    1.利用mysql5.7新增的sys.schema_auto_increment_columns 这是sys数据库下的一个视图,基础数据来自与information_schema,他的作用是对表的自增 ...

  10. mabatis的mapper文件找不到-ssm升级maven常见问题

    手里项目之前是普通ssm的,打算用业余时间升级一把. 1.首先,搭建好maven的ssm项目. 2.配置好jdk,tomcat环境,先启动. 3.启动没问题后将maven目录结构布置好后直接将原有项目 ...