题目地址:https://leetcode.cn/problems/lru-cache/description/?envType=study-plan-v2\&envId=top-100-liked
请你设计并实现一个满足 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) 的平均时间复杂度运行。
            
            
              go
              
              
            
          
          // 把 哈希表(map) 和 双向链表(doubly linked list) 结合:
// map 用于用键快速定位缓存节点(O(1)查找)。
// 双向链表维护使用顺序,链表头表示最近使用(MRU),链表尾表示最久未使用(LRU)。当容量超出时,从尾部删除节点并同时从 map 中移除。
type LRUCache struct {
	size     int
	capacity int
	cache    map[int]*DLinkedNode
	head     *DLinkedNode
	tail     *DLinkedNode
}
type DLinkedNode struct {
	key, val   int
	prev, next *DLinkedNode
}
func initDLinkedNode(key, val int) *DLinkedNode {
	return &DLinkedNode{key: key, val: val}
}
func Constructor(capacity int) LRUCache {
	lru := &LRUCache{
		size:     0,
		capacity: capacity,
		cache:    make(map[int]*DLinkedNode, capacity),
		head:     new(DLinkedNode),
		tail:     new(DLinkedNode),
	}
	lru.head.next = lru.tail
	lru.tail.prev = lru.head
	return *lru
}
// 在 map 中查找节点:
// 未命中:返回 -1(或指定的"未找到"值)
// 命中:返回值前,必须把该节点 移动到链表头部(标记为最近使用)
// 移动步骤(moveToHead):removeNode(node) ------ 将 node 从当前位置断开(调整前后节点指针)addToHead(node) ------ 将 node 插入到 head 后面
func (this *LRUCache) Get(key int) int {
	node := this.cache[key]
	if node != nil {
		this.moveToHead(node)
		return node.val
	}
	return -1
}
// 在 map 中查找是否已有该 key:若存在:更新 node.value;然后 moveToHead(node)
// 若不存在:构造新节点 node(key,value) addToHead(node) map[key] = node
// 如果 size == capacity,
// 则需要 evict:removed := removeTail() (取得 tail.prev)delete(map, removed.key)
// removeTail():取 tail.prev(真实尾节点),执行 removeNode(removed) 并返回 removed
func (this *LRUCache) Put(key int, value int) {
	node := this.cache[key]
	if node != nil {
		node.val = value
		this.cache[key] = node
		this.moveToHead(node)
		return
	}
	node = &DLinkedNode{key: key, val: value}
	if this.size == this.capacity {
		removed := this.removeTail()
		delete(this.cache, removed.key)
		this.size--
	}
	this.addToHead(node)
	this.size++
	this.cache[key] = node
}
// 对 双向链表的操作
func (lru *LRUCache) addToHead(node *DLinkedNode) {
	node.next = lru.head.next
	lru.head.next.prev = node
	lru.head.next = node
	node.prev = lru.head
}
func (lru *LRUCache) removeNode(node *DLinkedNode) {
	preNode := node.prev
	preNode.next = node.next
	node.next.prev = preNode
}
func (lru *LRUCache) moveToHead(node *DLinkedNode) {
	lru.removeNode(node)
	lru.addToHead(node)
}
func (lru *LRUCache) removeTail() *DLinkedNode {
	tail := lru.tail.prev
	lru.removeNode(tail)
	return tail
}