Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set. get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
实现least-recently-used cache,O(1)查找和添加,并且当cache容量达到限制时把最早没用过的元素踢出去。用双向链表配合hash表,用实体dummy head和tail能够不用检查next和pre是否为null,实现remove和add。O(1)找结点用hash map,每次接触过的节点放到头部,即调用一次remove和add。超出capacity就把tail前的元素移除。
Copy /*
* @lc app=leetcode id=146 lang=cpp
*
* [146] LRU Cache
*/
// @lc code=start
class LRUCache {
public:
class Node {
public:
int key, val;
Node *pre = nullptr, *next = nullptr;
Node(int k, int v): key(k), val(v) {}
};
Node *head, *tail;
unordered_map<int, Node*> m;
int K;
LRUCache(int capacity) {
head = new Node(-1, -1);
tail = new Node(-1, -1);
head->next = tail;
tail->pre = head;
K = capacity;
}
void rm(Node *node) {
node->pre->next = node->next;
node->next->pre = node->pre;
}
void add(Node *node) {
node->next = head->next;
node->pre = head;
head->next = node;
node->next->pre = node;
}
void update(Node *node) {
rm(node);
add(node);
}
int get(int key) {
if (!m.count(key)) return -1;
auto node = m[key];
update(node);
return node->val;
}
void put(int key, int value) {
if (m.count(key)) {
auto node = m[key];
node->val = value;
update(node);
} else {
Node *node = new Node(key, value);
if (m.size() == K) {
m.erase(tail->pre->key);
rm(tail->pre);
}
add(node);
m[key] = 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);
*/
// @lc code=end
Copy class LRUCache {
private class ListNode {
int key, val;
ListNode prior, next;
ListNode (int key, int val) {
this.key = key;
this.val = val;
prior = null;
next = null;
}
}
Map<Integer, ListNode> map;
ListNode head, tail = null;
int capacity, size;
public LRUCache(int capacity) {
this.capacity = capacity;
this.size = 0;
head = new ListNode(-1, 0);
tail = new ListNode(-1, 0);
head.next = tail;
tail.prior = head;
map = new HashMap<>();
}
private void rmNode(ListNode node) {
ListNode pre = node.prior;
ListNode next = node.next;
pre.next = next;
next.prior = pre;
}
// Add the new node right after head;
private void addNode(ListNode node) {
node.next = head.next;
node.prior = head;
node.next.prior = node;
head.next = node;
}
private void mv2Head(ListNode node) {
this.rmNode(node);
this.addNode(node);
}
private ListNode popTail() {
ListNode res = tail.prior;
rmNode(res);
return res;
}
public int get(int key) {
if (map.containsKey(key)) {
mv2Head(map.get(key));
return map.get(key).val;
} else {
return -1;
}
}
public void put(int key, int value) {
if (map.containsKey(key)) {
ListNode node = map.get(key);
mv2Head(node);
node.val = value;
} else {
size++;
ListNode node = new ListNode(key, value);
if (size > capacity) {
ListNode realTail = popTail();
map.remove(realTail.key);
size = capacity;
}
map.put(key, node);
addNode(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);
*/
每次set和get都是O(1).