LeetCode LRU缓存

题目地址: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
}
相关推荐
Learn Beyond Limits1 小时前
解构语义:从词向量到神经分类|Decoding Semantics: Word Vectors and Neural Classification
人工智能·算法·机器学习·ai·分类·数据挖掘·nlp
你怎么知道我是队长1 小时前
C语言---typedef
c语言·c++·算法
Qhumaing3 小时前
C++学习:【PTA】数据结构 7-1 实验7-1(最小生成树-Prim算法)
c++·学习·算法
代码N年归来仍是新手村成员4 小时前
【Java转Go】即时通信系统代码分析(一)基础Server 构建
java·开发语言·golang
踩坑记录4 小时前
leetcode hot100 3.无重复字符的最长子串 medium 滑动窗口(双指针)
python·leetcode
Z1Jxxx4 小时前
01序列01序列
开发语言·c++·算法
至善迎风5 小时前
Redis完全指南:从诞生到实战
数据库·redis·缓存
汽车仪器仪表相关领域6 小时前
全自动化精准检测,赋能高效年检——NHD-6108全自动远、近光检测仪项目实战分享
大数据·人工智能·功能测试·算法·安全·自动化·压力测试
Doro再努力6 小时前
【数据结构08】队列实现及练习
数据结构·算法