146.LRU缓存
题目:
解决方案
哈希表+双向链表
- 双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久未使用的。
- 哈希表即为普通的哈希映射(HashMap),通过缓存数据的键映射到其在双向链表中的位置。
这样一来,我们首先使用哈希表进行定位,找出缓存项在双向链表中的位置,随后将其移动到双向链表的头部,即可在 O(1) 的时间内完成 get 或者 put 操作。
个人认为单向链表任然可以实现,在具体实现中,由于要删除链表最后一个节点,单链表需要遍历到最后一个节点,所以使用双向链表。
代码:
/**
* @param {number} capacity
*/
class DLinkedNode {
constructor(key, value) {
this.key = key;
this.value = value;
this.prev = null;
this.next = null;
}
}
var LRUCache = function(capacity) {
this.hash = {};
this.head = new DLinkedNode();
this.tail = new DLinkedNode();
this.head.next = this.tail;
this.tail.prev = this.head;
this.capacity = capacity;
this.size = 0;
};
/**
* @param {number} key
* @return {number}
*/
LRUCache.prototype.get = function(key) {
if (this.hash[key]) {
let node = this.hash[key];
this.moveToHead(node);
return node.value;
}
return -1;
};
/**
* @param {number} key
* @param {number} value
* @return {void}
*/
LRUCache.prototype.put = function(key, value) {
console.log('put', key, value, this.hash[key])
if (!this.hash[key]) {
let node = new DLinkedNode(key, value);
this.hash[key] = node;
this.addToHead(node);
this.size++;
if (this.size > this.capacity) {
let node = this.removeTail();
delete this.hash[node.key];
this.size--;
}
} else {
let node = this.hash[key];
node.value = value;
this.moveToHead(node);
}
};
LRUCache.prototype.addToHead = function(node) {
node.prev = this.head;
node.next = this.head.next;
this.head.next.prev = node;
this.head.next = node;
}
LRUCache.prototype.removeNode = function(node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
LRUCache.prototype.moveToHead = function(node) {
// 两种方案
// 1.直接改变节点的指向
// 2.先删除后添加
this.removeNode(node);
this.addToHead(node);
}
LRUCache.prototype.removeTail = function() {
let node = this.tail.prev;
this.removeNode(node);
return node;
}
/**
* Your LRUCache object will be instantiated and called as such:
* var obj = new LRUCache(capacity)
* var param_1 = obj.get(key)
* obj.put(key,value)
*/
let lRUCache = new LRUCache(2);
console.log(lRUCache.put(1, 1)); // 缓存是 {1=1}
console.log(lRUCache.put(2, 2)); // 缓存是 {1=1, 2=2}
console.log(lRUCache.get(1)); // 返回 1
console.log(lRUCache.put(3, 3)); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
console.log(lRUCache.get(2)); // 返回 -1 (未找到)
console.log(lRUCache.put(4, 4)); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
console.log(lRUCache.get(1)); // 返回 -1 (未找到)
console.log(lRUCache.get(3)); // 返回 3
console.log(lRUCache.get(4)); // 返回 4