Solution 1
LRU是操作系统的主要知识点之一。
整个过程可以使用链表实现,但是考虑到要求存取都在常数时间,因此这里需要额外的调整。
- 查找需要使用一个额外的哈希表
- 链表改成一个双向链表,这样就可直接用头尾表示最近使用和最早使用页面
剩下的就是核心部分的页面替换实现了。
- 时间复杂度: O ( 1 ) O(1) O(1),按照要求必须在常数时间内实现
- 空间复杂度: O ( c a p a c i t y ) O(capacity) O(capacity),其中 c a p a c i t y capacity capacity为指定的缓存容量,哈希表和节点数据结构占用
class LRUNode{
// 双向链表节点实现
public:
int key;
int value;
LRUNode* prev;
LRUNode* next;
LRUNode() {
this->key = 0;
this->value = 0;
this->prev = nullptr;
this->next = nullptr;
}
LRUNode(int key, int value) {
this->key = key;
this->value = value;
this->prev = nullptr;
this->next = nullptr;
}
};
class LRUCache {
public:
LRUCache(int capacity) {
// cout << "CREATE" << endl;
this->capacity = capacity;
this->size = 0;
this->head = new LRUNode();
this->tail = new LRUNode();
this->head->next = this->tail;
this->tail->prev = this->head;
}
int get(int key) {
// cout << "GET" << " k:" << key << " ";
if (this->cache.find(key) != this->cache.end()) {
// LRU读: 访问到,直接移到头部
// cout << "Found!" << " ";
auto cur = this->cache[key];
this->remove(cur);
this->addHead(cur);
return cur->value;
} else {
// LRU读:未访问到,返回-1
// cout << "NotFound!" << " ";
return -1;
}
// cout << endl;
}
void put(int key, int value) {
// cout << "PUT" << " k:" << key << " v:" << value << " ";
if (this->cache.find(key) != this->cache.end()) {
// LRU写: 访问到,更新值,直接移到头部
// cout << "Found!" << " ";
auto cur = this->cache[key];
cur->value = value;
this->remove(cur);
this->addHead(cur);
} else {
// LRU写:未访问到,创建节点,直接移到头部
// cout << "NotFound!" << " ";
auto cur = new LRUNode(key, value);
this->cache[key] = cur;
this->addHead(cur);
this->size++;
// LRU写:关键,如果超过了容量,去掉最后的内容
if (this->size > this->capacity) {
// 删节点,清表
auto bad = this->removeTail();
this->cache.erase(bad->key);
this->size--;
}
}
cout << endl;
}
private:
int capacity; // 容量
int size; // 实际大小
// 双线链表,head和tail表示头尾
unordered_map<int, LRUNode*> cache;
LRUNode* head;
LRUNode* tail;
void addHead(LRUNode* node) {
// cout << "AddHead!" << " k:" << node->key << " v:" << node->value << " ";
node->prev = this->head;
node->next = this->head->next;
this->head->next->prev = node;
this->head->next = node;
}
void remove(LRUNode* node) {
// cout << "Remove!" << " ";
node->next->prev = node->prev;
node->prev->next = node->next;
}
LRUNode* removeTail() {
// cout << "RemoveTail!" << " ";
auto node = this->tail->prev;
this->remove(node);
return node;
}
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
Solution 2
Solution 1的Python实现
class LRUNode:
def __init__(self, key=0, value=0):
self.key = key
self.value = value
self.prev = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.size = 0
self.head = LRUNode()
self.tail = LRUNode()
self.head.next = self.tail
self.tail.prev = self.head
self.cache = dict()
def get(self, key: int) -> int:
if key in self.cache:
cur = self.cache[key]
self.remove(cur)
self.addHead(cur)
return cur.value
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
cur = self.cache[key]
cur.value = value
self.remove(cur)
self.addHead(cur)
else:
cur = LRUNode(key, value)
self.cache[key] = cur
self.addHead(cur)
self.size += 1
if self.size > self.capacity:
bad = self.removeTail()
self.cache.pop(bad.key)
self.size -= 1
def addHead(self, node):
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node
def remove(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def removeTail(self):
node = self.tail.prev
self.remove(node)
return node
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)