题目

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:

LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
示例:

输入
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4

题解

LRU (最近最少使用) 缓存

LRU,Least Recently Used算法,即一种缓存淘汰策略。计算机的缓存容量有限,若缓存满了则需要删除一些内容,给新的缓存腾出空间,但问题是要删除哪些内容呢?这需要相应的缓存策略来实现。
缓存淘汰的策略有很多,而LRU则是一种较为简单常用的算法,LRU判定最近使用过的数据为有用的,很久都没用过的数据是无用的,在内存满了就优先删除很久未使用,也就是无用的数据。

解题思路

本题的关键在于数据增加查找时都需要改变所有数据的优先级,要在O(1)的复杂度内实现,显然需要用到链表+map的组合,为快速实现链表结点查找与修改,需要使用到双向链表。
因此,解题方法为:“map+双向链表”,map保存键值为数据的key与双向链表结点,便于快速查找对应结点。双向链表维护了数据的优先级信息,优先级最高的在最前,最低在最后。具体的,设置两个哨兵结点——>哨兵头结点(head)与哨兵尾结点(tail),便于发生插入/删除操作时的操作。

代码

// 双向链表 + map
// 双向链表维护数据使用的次序,最久未使用在最前,最新在最后// 构建双向链表类,记录缓存优先级信息
class DlinkNode
{public:DlinkNode* prev;DlinkNode* next;int key, value;DlinkNode():prev(nullptr), next(nullptr), key(0), value(0){}DlinkNode(int key_, int value_):prev(nullptr), next(nullptr), key(key_), value(value_){}
};class LRUCache {public:LRUCache(int capacity_):capacity(capacity_), size(0){// head, tail哨兵节点, head->next 为头节点, tail->prev为尾节点head = new DlinkNode();tail = new DlinkNode();head->next = tail;tail->prev = head;}int get(int key) {// 如果存在,将结点挪到头部 if(mp.count(key)){DlinkNode* node = mp[key];move2Head(node);return node->value;}return -1;}void put(int key, int value) {if(!mp.count(key)){// 不存在,创建新节点,添加进哈希表并放入表头DlinkNode* node = new DlinkNode(key, value);add2Head(node);mp[key] = node;size++;if(size > capacity){// 超出容量,删除尾部DlinkNode* removed = removeTail();mp.erase(removed->key);delete removed;size--;}}else{DlinkNode* node = mp[key];node->value = value;move2Head(node);}}void add2Head(DlinkNode* node){node->prev = head;node->next = head->next;head->next->prev = node;head->next = node;  }void removeNode(DlinkNode* node){node->prev->next = node->next;node->next->prev = node->prev;}void move2Head(DlinkNode* node){removeNode(node);add2Head(node);}// 删除最后的结点,及tail前的结点DlinkNode* removeTail(){DlinkNode* node = tail->prev;removeNode(node);return node;}private:int size;int capacity;map<int, DlinkNode*> mp;DlinkNode* head;DlinkNode* tail;
};

面试常考题——LRU缓存题解相关推荐

  1. 算法人必懂的进阶SQL知识,4道面试常考题

    (图片付费下载自视觉中国) 作者 | 石晓文 来源|小小挖掘机(ID:wAlsjwj) 近期在不同群里有小伙伴们提出了一些在面试和笔试中遇到的Hive SQL问题,Hive作为算法工程师的一项必备技能 ...

  2. 高职单招面试自我介绍稿子计算机专业,高职单招面试自我介绍范文及面试常考题...

    如何在高职单招面试中进行自我介绍呢?对很多缺乏社会经验的考生来说,要熟悉各种各样的面试技巧,然后要懂得临场发挥,不然很有可能因为慌张而导致语无伦次,把单招面试弄砸. 单招面试自我介绍范文 各位老师好, ...

  3. 面试常考题---交换变量

    1 面试常考的试题:(交换两个变量值,不使用第三方变量) 2 方法1: int n1=50; 3 int n2=30; 4 //最终结果n1=30 n2=50 5 6 n1=n1-n2;//n1=20 ...

  4. 面试常考!缓存三大问题及解决方案

    1. 缓存来由 随着互联网系统发展的逐步完善,提高系统的qps,目前的绝大部分系统都增加了缓存机制从而避免请求过多的直接与数据库操作从而造成系统瓶颈,极大的提升了用户体验和系统稳定性. 2. 缓存问题 ...

  5. 前端面试常考题:JS垃圾回收机制

    摘要:众所周知,应用程序在运行过程中需要占用一定的内存空间,且在运行过后就必须将不再用到的内存释放掉,否则就会出现下图中内存的占用持续升高的情况,一方面会影响程序的运行速度,另一方面严重的话则会导致整 ...

  6. 网络技术/技术支持岗位在网络安全大厂/互联网公司笔试面试常考题-计算机网络知识点总结

    目录 1.OSI七层模型及各层作用 2.TCP/IP模型 3.ARP地址解析协议(工作在网络层和数据链路层) 4.MAC层的功能&MAC地址的作用 MAC层功能: MAC地址作用​​​​​​什 ...

  7. 合肥Java面试常考题_北大青鸟java 面试--常见面试题(中)

    上一文中,我们总结了java面试的基础,多线程,jvm的常见面试题,本文合肥北大青鸟合工大校区的袁老师继续介绍面试中网络.数据结构和算法.分布式理论和微服务的常见面试题. 一.网络 网络的话,主要集中 ...

  8. HTTP 和 HTTPS 的区别(面试常考题)

    前言 无论是在校学习还是找工作的时候,老师和面试官都问过同学 HTTP 和 HTTPS 的区别.平时上网的时候也没有关注这个问题,只是知道计算机网络里 HTTP 的概念,所以最近才查资料好好补补这一块 ...

  9. 阿里大佬耗时一年整理的Java面试常考题

    就目前大环境来看,跳槽成功的难度比往年高很多.一个明显的感受:今年的面试,无论一面还是二面,都很考验Java程序员的技术功底.这不马上又到了面试跳槽的黄金段,成功升职加薪,不成功饱受打击.当然也要注意 ...

  10. 面试常考题:不调用库函数,怎样实现字符串操作函数?

    一:字符串操作函数的功能及应用 1.strcpy()函数Strcpy(字符数组1,字符数组2)此函数是字符串拷贝函数,它的作用是将字符串2复制到字符数组1中去. #include<stdio.h ...

最新文章

  1. USACO_2_3_Controlling Companies
  2. Acid: 单网页检查页面,浏览器兼容性测试,浏览器好坏的标志
  3. TensorFlow学习笔记(二十五)CNN的9大模型
  4. fastjson SerializerFeature详解
  5. 香港连续25年被评为全球最自由经济体
  6. Spark算子---实战应用
  7. 微信JS图片上传与下载功能--微信JS系列文章(三)
  8. 如何做出好的文档 (要学习前人的经验,不要闭门造车)
  9. Spring之占位符配置器
  10. 应用代理 socket TCP协议 的资料
  11. C++实现PCA变换
  12. 高数__已知2个平面方程, 求这2个平面的夹角
  13. 2021年P气瓶充装模拟考试及P气瓶充装考试试题
  14. 图扑软件以轻量化建模构建智慧城市
  15. VRay Next for SketchUp 赋予材质常见问题
  16. Canvas绘制六边形网格
  17. 微信java精简版低内存_微信精简版低内存apk-微信精简版2019下载v7.0.6 安卓版-腾牛安卓网...
  18. 网站备案其实是服务器备案,国内服务器为什么需要备案?国外服务器备案吗?
  19. git使用大全,强大的项目管理工具
  20. 【已解决】模拟人生4(Sims4) 启动失败 orangeEmu.dll及应用程序错误0x0000142

热门文章

  1. 大数据周周看:金融科技公司融360赴美IPO,小蓝单车人去楼空,用户押金退还困难
  2. Sublime txt文本编辑器快捷方式简介
  3. 淘宝大数据之流式计算
  4. iOS最简单的方式实现在线播放音频。
  5. ecshop模板基础知识
  6. MySQL的锁到底有多少内容?和腾讯大佬的技术面谈,我真菜
  7. cmd命令打开文本文档_win7定时关机命令 【处置技巧】
  8. 小程序上传图片报错MiniProgramError “createUploadTask:fail url not in domain list“ 解决方案
  9. DirectX11 With Windows SDK--28 计算着色器:波浪(水波)
  10. 第一课print()输出函数(包含心形图案代码)