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).