请你设计并实现一个满足 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提示:
1 <= capacity <= 30000 <= key <= 100000 <= value <= 105- 最多调用
2 * 105次get和put
思路:

时间复杂度:get()、put()方法,由于是hash链表的数据结构,通过空间换时间的方式,均为O(1)
空间复杂度:get()、put()方法,由于是hash链表的数据结构,通过空间换时间的方式,均为O(1)
- type LinkNode struct {
- key, val int
- pre, next *LinkNode
- }
-
- // 其中head和tail都为虚拟节点,不存储实际数据,仅用于标记双向链表首尾位置
- type LRUCache struct {
- m map[int]*LinkNode
- cap int
- head, tail *LinkNode
- }
-
- func Constructor(capacity int) LRUCache {
- head := &LinkNode{0, 0, nil, nil}
- tail := &LinkNode{0, 0, nil, nil}
- head.next = tail
- tail.pre = head
- return LRUCache{make(map[int]*LinkNode), capacity, head, tail}
- }
-
- func (this *LRUCache) Get(key int) int {
- cache := this.m
- if v, exist := cache[key]; exist {
- this.MoveToHead(v)
- return v.val
- } else {
- return -1
- }
- }
-
- func (this *LRUCache) Put(key int, value int) {
- tail := this.tail
- cache := this.m
- if v, exist := cache[key]; exist {
- // 若存在:更新值并将该节点移动到最前
- v.val = value
- this.MoveToHead(v)
- } else {
- // 若不存在:判断链表容量是否已满,若满则移除链表尾元素后再加入新节点到链表,未满则直接加入
- v := &LinkNode{key, value, nil, nil}
-
- // 超出容量cap,删除最后元素
- if len(cache) == this.cap {
- delete(cache, tail.pre.key)
-
- // tail是虚拟的尾节点,移除 tail.pre 等同于下面两句
- this.RemoveNode(tail.pre)
- // tail.pre.pre.next = tail
- // tail.pre = tail.pre.pre
- }
- this.AddNode(v)
- cache[key] = v
- }
- }
-
- // 以下为内部公共函数
- // 访问过某节点元素,则将该节点元素从当前位置移除并重新加入到首位置
- func (this *LRUCache) MoveToHead(node *LinkNode) {
- this.RemoveNode(node)
- this.AddNode(node)
- }
-
- // 移除某节点元素
- func (this *LRUCache) RemoveNode(node *LinkNode) {
- node.pre.next = node.next
- node.next.pre = node.pre
- }
-
- // 将某节点元素重新加入到首位置
- func (this *LRUCache) AddNode(node *LinkNode) {
- head := this.head
- node.next = head.next
- head.next.pre = node
- node.pre = head
- head.next = node
- }