package main
import (
"container/list"
)
/*
LRU 缓存 (Least Recently Used)
设计思路:
1. 使用一个双向链表 (list.List) + 一个哈希表 (map) 来实现。
- 双向链表保存元素的访问顺序,最新使用的放在表头,最久未使用的放在表尾。
- 哈希表用来快速定位 key 对应的链表节点,实现 O(1) 查找。
2. 每次访问 (get) 时,如果 key 存在:
- 将对应的节点移到链表头部(表示最近使用过)。
- 返回节点的 value。
- 时间复杂度 O(1)。
3. 每次插入 (set) 时:
- 如果 key 已存在:更新 value,并将节点移到链表头部。
- 如果 key 不存在:新建一个节点插入链表头部,并在 map 中保存 key→节点的映射。
- 插入后如果超过容量,需要删除链表尾部的节点,同时从 map 中移除对应的 key。
- 时间复杂度 O(1)。
4. 这样可以保证:
- 查找、更新、插入和淘汰都在常数时间内完成。
*/
type LRUElement struct {
value int // 缓存的值
key int // 缓存的键,用于淘汰时从 map 中删除
}
type Solution struct {
linkedList *list.List // 双向链表,保存元素的访问顺序
dataMap map[int]*list.Element // 哈希表,key → 链表节点
capacity int // 缓存容量
}
// Constructor 初始化 LRU 缓存,指定最大容量
func Constructor(capacity int) Solution {
return Solution{
linkedList: list.New(), // 新建一个空的双向链表
dataMap: make(map[int]*list.Element), // 初始化哈希表
capacity: capacity, // 设置容量
}
}
// get 获取 key 对应的 value
// 如果 key 存在,将对应节点移到链表头部(表示最近使用过),并返回值
// 如果 key 不存在,返回 -1
func (this *Solution) get(key int) int {
if existElement, ok := this.dataMap[key]; ok {
// 移动到链表头部
this.linkedList.MoveToFront(existElement)
// 返回值
return existElement.Value.(*LRUElement).value
}
return -1
}
// set 插入或更新 key-value
// 如果 key 已存在,更新 value 并移到链表头部
// 如果 key 不存在,新建节点放到链表头部
// 插入后如果超过容量,淘汰链表尾部节点(最久未使用的)
func (this *Solution) set(key int, value int) {
// key 已存在 → 更新 value,移到头部
if existElement, ok := this.dataMap[key]; ok {
existElement.Value.(*LRUElement).value = value
this.linkedList.MoveToFront(existElement)
return
}
// key 不存在 → 插入新节点到头部
elem := &LRUElement{value: value, key: key}
listElem := this.linkedList.PushFront(elem)
this.dataMap[key] = listElem
// 如果超过容量 → 删除尾部节点
if this.linkedList.Len() > this.capacity {
backElem := this.linkedList.Back()
if backElem != nil {
// 找到尾部元素
deleteLruElement := backElem.Value.(*LRUElement)
// 从 map 中删除
delete(this.dataMap, deleteLruElement.key)
// 从链表中删除
this.linkedList.Remove(backElem)
}
}
}