146.LRU缓存机制-python
146.LRU缓存机制(中等)
题目大意:
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
- LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
- int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
- void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
题目
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:
- LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
- int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
- void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
示例:
1 |
|
提示:
- 1 <= capacity <= 3000
- 0 <= key <= 10000
- 0 <= value <= 105
- 最多调用 2 * 105 次 get 和 put
解答与分析
这个题实在是太经典了,而且是自己面试过程中真正被问到而没有做出来的题目,首先第一步要根据题目所给出的内容自定义LRUCache类,也借此进一步熟悉语法。
自定义LRUCache类
1 |
|
使用双向链表来完成题目要求的操作时间复杂度要求
题目中要求的O(1)时间复杂度下完成各个操作,主要靠的是cache词典和双向链表中的一些操作,缓存(cache)在这个题中十分关键
首先搞起来双向链表的基本模板
1 |
|
LRUCache __init__中需要初始化的内容
按照题目一步步的来分析,首先分析需要哪些内容放在LRUcatch的init中,首先是题目中给了的capacity代表这个LRU cache的最大容量,之后是一个为0的current_size代表当前LRU cache的容量,之后可以根据做一些特殊的判断。还有就是一个词典的cache,代表有哪些已经在LRUcache中了,这里最关键的是记住这个cache中存储的是key-node的mapping。还有就是初始化一个双向链表,注意这个双向链表的头和尾虽然直接初始化了,但是这两个节点并没有什么含义,所以head.next和tail.prev中间这些的才感觉是有用的。
1 |
|
分析LRUCache中的插入(put)操作和查找(get)操作
插入(put)
插入给了一个key和一个value。
首先判断key是不是已经在cache中了
如果已经在cache中了
- 在cache中删除这个key对应的node,然后把这个节点的更新值头插法搞到链表的最前边去。这里体现了双向链表的作用还有cache中key-node mapping的作用,,mapping找到一个node后,基于双向链表可完成O(1)的删除
如果不在的话
- 首先判断目前的self.current_size和self.capacity的关系,
- 如果相等了,则删除目前双向链表尾部的,之后用头插法在前边插入上。
- 如果self.current_size小于self.capacity,直接在头部插入后,self.capacity++就可以了
- 首先判断目前的self.current_size和self.capacity的关系,
查找(get)
查找只给了一个key,返回这个key对应的value,如果找不到就返回-1
这个直接从cache中找就可以了,但是注意查找到的同样要删除,并且头插法到最前边来
双向链表操作函数的编写
综上所述,在该题中需要双向链表的三种操作:(注意这里只管链表的操作,是否能执行这些操作的判断在其他地方试)
①头插法
②尾部删除:特别注意这里的尾部删除,在超出capacity的时候会执行尾部删除,这个时候要拿到尾部删除后的node,以便从cache中将其移除!!!!!!!!
③中间删除
下边这些实现还要经常复习,主要是涉及顺序
1 |
|
工具都造好了,最终整体上的代码实现如下,还要经常复习啊
1 |
|