算法学习笔记-LeetCode146.LRU缓存

请你设计并实现一个满足 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) 的平均时间复杂度运行。

分析
一道经典的算法题,可以背下来,但是最好整理一下思路:
1,缓存有容量限制,为了避免超出容量限制,一般会用一个属性size记录缓存内数据的数目。
2,需要以O(1)的时间复杂度查找一个数据,一般是用哈希表实现的,其他数据结构没有那么快。也就是说,我们需要把所有数据存入一个哈希表中,对于每个要查找的数据,能快速从表中取出这个数据。
3,关键字存在则变更数据,不存在则插入数据,超出容量则逐出一个数据,直到这里的要求,哈希表都是可以满足的,但是该题还要求逐出最久未使用的关键字,哈希表无法快捷有效地做到查找到最久未使用的关键字,因为哈希表逻辑上是没有顺序的,所以为了使数据具有顺序性,需要一个线性的数据结构,而且这个数据需要能便捷地在任意位置进行插入删除操作,这样才能做到当访问过已有的某个数据时,把它的位置调整到数据开头,这种数据结构显然就是双向链表。但是双向链表无法进行随机访问,不过这个问题反过来又被哈希表解决,两个数据结构的组合可以完美地实现LRU功能。
总结
1,哈希表的作用是对于给定的关键字,定位到这个数据,实现O(1)的查找时间复杂度。
2,链表的作用是使得数据具有前后顺序性,即记录数据访问的时间顺序,把访问过的数据放到链表的开头就可以表示该数据最近访问过,如果要删除数据需要最后删除。
3,总的来说,总的数据结构就是快速随机查找,有顺序,可以快速随机删除插入。其中哈希表用来实现第一点,链表用来实现第二,三点。
4,可以把数据结构看成核心是一个双向链表,而哈希表的作用是实现随机查找。
细节
1,数据用内部类DLinkedNode表示,每个Node有关键字key和数据值val,一个key对应一个Node。

Node中为什么一定要存key?
Node中key的必要性在于,当从链表中删除一个Node时,需要取出对应的key,这样才能从哈希表中删除掉这个Node,因为哈希表是通过key查找Node的。

那为什么哈希表不能直接存Node?
因为题目要求就是通过key查找数据。

因为需要通过Key查找Node,所以哈希表是<key,Node>形式。因为删除数据时需要知道数据对应的key,所以Node中要有key。因为链表中的数据存的是Node,所以要通过Node才能得到key。因为删除数据是找到最近最久未使用的数据,所以只能从链表中找到删除的数据Node。

即:
找到链表中待删除的Node,删除这个Node,从Node中取出key,通过Key删除哈希表中的数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值