LeetCode 146. LRU缓存机制
yinxin630 opened this issue · comments
题目
https://leetcode-cn.com/problems/lru-cache/submissions/
思路
- 使用Map记录缓存值, 使用链表记录缓存操作顺序, 最后操作的缓存置于链表头部, 链表尾部就是最少操作的缓存
- 读取缓存时, 更新缓存操作顺序, 将缓存节点从链表中移除, 再将其添加到链表头部. 移除节点时要保证链表的连续性, 为了在O(1)时间完成该操作, 需要使用双向链表
- 设置缓存时, 如果是已存在的缓存, 则直接更新缓存值即可, 并更新缓存操作顺序. 如果是不存在的缓存, 将缓存加到链表头部, 添加后如果缓存超过了上限, 则将链表尾部的缓存清除掉
代码
class DoubleLinkList {
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
unshift(node) {
if (this.head && this.tail) {
node.prev = null;
node.next = this.head;
this.head.prev = node;
this.head = node;
} else {
node.prev = node.next = null;
this.head = this.tail = node;
}
this.length++;
return node;
}
pop() {
if (this.tail) {
const node = this.tail;
if (this.head === this.tail) {
this.head = this.tail = null;
} else {
this.tail.prev.next = null;
this.tail = this.tail.prev;
}
this.length--;
return node;
}
}
remove(node) {
if (node !== this.head && node !== this.tail) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
if (node === this.head) {
this.head = this.head.next;
}
if (node === this.tail) {
this.tail = this.tail.prev;
}
this.length--;
}
}
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.list = new DoubleLinkList();
this.map = new Map();
}
get(key) {
let node = this.map.get(key);
if (node) {
this.list.remove(node);
this.list.unshift(node);
return node.value;
} else {
return -1;
}
}
put(key, value) {
let node = this.map.get(key);
if (node) {
node.value = value;
this.list.remove(node);
this.list.unshift(node);
} else {
node = { key, value };
this.list.unshift(node);
this.map.set(key, node);
if (this.list.length > this.capacity) {
const tail = this.list.pop();
this.map.delete(tail.key);
}
}
}
}
Map这种数据结构本身遍历是有顺序的 按照插入的顺序遍历 所以可以不用链表来记住顺序