运用你所掌握的数据结构,设计和实现一个  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 在解答这到题之前我们先看看看什么是LRU

LRU (英文:Least Recently Used )它是内存管理的一种页面置换算法,对于在内存中但又不用的数据块(内存块)叫做LRU,操作系统会根据哪些数据属于LRU而将其移出内存而腾出空间来加载另外的数据。

LRU算法:最近最少使用,简单来说就是将数据块中,每次使用过的数据放在数据块的最前端,然后将存在的时间最长的,也就是数据块的末端的数据剔除掉,这个算法的精髓在于如果一块数据最近被访问,那么它将来被访问的几率也很高,根据数据的历史访问来淘汰长时间未使用的数据,这就是LRU算法。

那么为什么需要这个算法呢??

  关于操作系统的内存管理,如何节省利用容量不大的内存为最多的进程提供资源,一直是研究的重要方向。而内存的虚拟存储管理,是现在最通用,最成功的方式—— 在内存有限的情况下,扩展一部分外存作为虚拟内存,真正的内存只存储当前运行时所用得到信息。这无疑极大地扩充了内存的功能,极大地提高了计算机的并发度。虚拟页式存储管理,则是将进程所需空间划分为多个页面,内存中只存放当前所需页面,其余页面放入外存的管理方式。
  然而,有利就有弊,虚拟页式存储管理增加了进程所需的内存空间,却也带来了运行时间变长这一缺点:进程运行过程中,不可避免地要把在外存中存放的一些信息和内存中已有的进行交换,由于外存的低速,这一步骤所花费的时间不可忽略。因而,采取尽量好的算法以减少读取外存的次数,也是相当有意义的事情。
所以,我们解题的思路就出来了:
  1.我们需要用栈的思想来想一下。栈顶就是最近刚访问的,而栈底就是最久没访问过的。
  2.需要以个HashMap来保证里面的数据不重复。
需要明确的:
  1.添加节点:新节点插入到表头即可,时间复杂度O(1)
  2.查找节点:每次节点被查询到时,将节点移动到链表头部,时间复杂度O(n)
  3. 替换节点:查找到后替换(更新节点value),将节点移动到链表头部;
对于下一个页面的情况;
  1.栈中存在:则需要更新栈顶元素,就是将当前存在的页号放到栈顶。
  2.栈中并未存在:
    2.1.栈未满:直接将该页放到栈顶。
    2.2.栈已满:需要选一个最近最久未访问的将它置换出,然后将该页放到栈顶。
代码如下
class LRUCache {
private HashMap<Integer,Integer> map;
private Stack<Integer> stack;
private int size; public LRUCache(int capacity) {
map = new HashMap<>(capacity);
stack = new Stack<Integer>();
size = capacity;
} public int get(int key) {
if(!stack.contains(key)){
return -1;
}
boolean old = stack.remove(Integer.valueOf(key)); //栈中存在
stack.push(key);
return map.get(key);
} public void put(int key, int value) {
if(stack.contains(key)){
stack.remove(Integer.valueOf(key));
}else{
if(stack.size() == size){
int count = stack.remove(0);
map.remove(count); }
}
stack.add(key);
map.put(key,value);
}
}

LRU缓存机制的更多相关文章

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

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

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

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

  3. 常见面试题之操作系统中的LRU缓存机制实现

    LRU缓存机制,全称Least Recently Used,字面意思就是最近最少使用,是一种缓存淘汰策略.换句话说,LRU机制就是认为最近使用的数据是有用的,很久没用过的数据是无用的,当内存满了就优先 ...

  4. Q200510-03-03 :LRU缓存机制

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

  5. Q200510-03-02: LRU缓存机制

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

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

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

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

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

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

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

  9. 【力扣】146. LRU缓存机制

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

  10. [Swift]LeetCode146. LRU缓存机制 | LRU Cache

    Design and implement a data structure for Least Recently Used (LRU) cache. It should support the fol ...

随机推荐

  1. bzoj4516 / P4070 [SDOI2016]生成魔咒

    P4070 [SDOI2016]生成魔咒 后缀自动机 每插入一个字符,对答案的贡献为$len[last]-len[fa[last]]$ 插入字符范围过大,所以使用$map$存储. (去掉第35行就是裸 ...

  2. Mysql报错java.sql.SQLException:null,message from server:"Host '27,45,38,132' is not allowed to connect

    Mysql报错java.sql.SQLException:null,message from server:"Host '27,45,38,132' is not allowed to co ...

  3. Linux 流量监控工具 iftop

    Linux 流量监控工具 iftop Iftop工具主要用来显示本机网络流量情况及各相互通信的流量集合,如单独同哪台机器间的流量大小,非常适合于代理服务器和iptables服务器使用,这样可以方便的查 ...

  4. mysql不常用但很有用的语句整理

    mysqld_multi多实例停止.启动 mysqld_multi --defaults-file=/etc/my.cnf start 1,2 mysqld_multi --defaults-file ...

  5. rabbitmq级联之shovel插件和exchange.bind

    有时候,由于各方面原因比如安全原因.系统间隔离,我们需要实现在多个rabbitmq实例或者一个rabbitmq实例的多个vhost间推送消息.在上一版的实现中,公司使用java自行实现了一个类似转发器 ...

  6. Ubuntu + CUDA9 + CUDNN7 + OpenCV3.4 + contrib +CAFFE-master

    安装ubuntu时赞美Rufus(建议ubuntu16.04.04),过程参考 https://www.cnblogs.com/willnote/p/6725594.html 安 装 前 一 定 要 ...

  7. 转载:Systemd 服务配置文件

    目录 一.开机启动 二.启动服务 三.停止服务 四.读懂配置文件 五. [Unit] 区块:启动顺序与依赖关系. 六.[Service] 区块:启动行为 6.1 启动命令 6.2 启动类型 6.3 重 ...

  8. 完全卸载oraclean安装

    完全卸载oracle11g步骤:1. 开始->设置->控制面板->管理工具->服务 停止所有Oracle服务.2. 开始->程序->Oracle - OraHome ...

  9. Oracle 之 函数运用

    NVL函数:NVL(a,b)就是判断a是否是NULL,如果不是返回a的值,如果是返回b的值 通过查询获得某个字段的合计值,如果这个值位null将给出一个预设的默认值 通过nvl 对定义值赋值的语法: ...

  10. P4313 文理分科

    思路 遇到这种利益冲突的最终利益最大化问题 考虑转化为最小割,使得损失的价值最小 相当于文科是S,理科是T,选出最小割就是确定损失代价最小的方案 然后就把S向每个点连一条cap=art[i][j]的边 ...