运用你所掌握的数据结构,设计和实现一个  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. thinkphp5 目录结构

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

  2. [bzoj1741]穿越小行星群

    将每一行/每一列作为一个点,对于一个障碍(x,y),要么第x行和第y列的状态(是否攻击)只需要有一个就可以了,将第x行和第y列连边,就是二分图的最小点覆盖=最大匹配数. 1 #include<b ...

  3. [cf1217F]Forced Online Queries Problem

    可以用并查集维护连通性,删除可以用按置合并并查集,但删掉一条边后无法再维护两点的联通性了(因为产生环的边是不加入的)暴力思路是, 考虑前i个操作后边的集合,暴力加入即可,但复杂度是$o(n^2)$的用 ...

  4. [luogu3706]硬币游戏

    (可以参考洛谷4548,推导过程较为省略) 定义$g_{i}$表示随机$i$次后未出现给定字符串的概率,$f_{k,i}$表示随机$i$次后恰好出现$s_{k}$(指第$k$个字符串)的概率,设两者的 ...

  5. maven私服-账号管理

    关于maven私服的相关数据: 默认账号admin,密码:admin123 这个账号是不能进行上传代码 到maven仓库的. 我们光是有admin和匿名账号是不够的,我们需要创建一个专门用来部署的账号 ...

  6. electron另一种运行方式

    编写helloword 全局安装软件  npm install -g electron 快速编写html  html:5 完整代码和流程: 1.index.html  <!DOCTYPE htm ...

  7. 推荐几款谷歌浏览器(chrome)超实用的插件

    1.github加速器 在谷歌应用商店搜索"Github加速器",安装即可. 说明:在国内访问github有时候非常慢,是让人非常头疼的一件事,安装这个插件后 大大加快github ...

  8. Java 代码审计 — 1. ClassLoader

    参考: https://www.bilibili.com/video/BV1go4y197cL/ https://www.baeldung.com/java-classloaders https:// ...

  9. Android连接远程数据库的避坑指南

    Android连接远程数据库的避坑指南 今天用Android Studio连接数据库时候,写了个测试连接的按钮,然后连接的时候报错了,报错信息: 2021-09-07 22:45:20.433 705 ...

  10. 解决texlive化学式转换镜像经常偶发性进程堆积导致卡顿问题

    前言 之前在 使用Python定时清理运行超时的pdflatex僵尸进程 博文中我采用python脚本开启定时任务清理pdflatex僵尸进程,线上4u2G的k8s pod部署了3个,pdflatex ...