最近有个小伙伴跟我诉苦,说他没面到LRU,他说他很久前知道有被问过LRU的但是心想自己应该不会遇到,所以暂时就没准备。
奈何不巧,这还就真的考到了!他此刻的心情,可以用一张图来证明:
他说他最终踉踉跄跄的写了一个效率不是很高的LRU,面试官看着不是很满意……后来果真GG了。
防止日后再碰到这个坑,今天和大家一起把这个坑踩了,这道题我自身刚开始也是用较为普通的方法,但是好的方法虽然不是很难但是想了真的很久才想到,虽然花了太多时间不太值,总算是自己想出来了,将这个过程给大家分享一下(只从算法的角度,不从操作系统的角度)。
理解LRU
设计一个LRU,你得知道什么是LRU吧?
LRU,英文全称为Least Recently Used,翻译过来就是最近最久未使用算法,是一种常用的页面置换算法。
说起页面置换算法,这就是跟OS关系比较大的了,我们都知道内存的速度比较快,但是内存的容量是非常有限的,不可能给所有页面装到内存中,所以就需要一个策略将常用的页面预放到内存中。
但是吧,谁也不知道进程下次会访问哪个内存,并不能很有效的知道(我们在当前并没有预测未来的功能),所以有些页面置换算法只是理想化但是没法真实实现的(没错就是最佳置换算法(Optimal)),然后常见必回的算法就是FIFO(先进先出)和LRU(最近最久未使用)。
LRU理解不难,就是维护一个有固定大小的容器,核心就是get()和put()两个操作。
我们先看一下LRU会有的两个操作:
初始化:LRUCache(int capacity) ,以正整数作为容量 capacity 初始化 LRU 缓存。
查询:get(int key),从自己的设计的数据结构中查找是否有当前key对应的value,如果有那么返回对应值并且要将key更新记录为最近使用,如果没有返回-1。
插入/更新:put(int key,int value),可能是插入一个key-value,也可能是更新一个key-value,如果容器中已经存才这个key-value那么只需要更新对应value值,并且标记成最新。如果容器不存在这个值,那么要考虑容器是否满了,如果满了要先删除最久未使用的那对key-value。
这里的流程可以给大家举个例子,例如
容量大小为2:
[ "put", "put", "get", "put","get", "put","get","get","get"]