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.
[code]
class LRUCache {
DoubleLinkedList cache;
HashMap<Integer, DoubleLinkedListNode>map;
int capacity;
int size;
public LRUCache(int capacity) {
cache=new DoubleLinkedList();
map=new HashMap<Integer, DoubleLinkedListNode>();
this.capacity=capacity;
size=0;
}
public int get(int key) {
if(map.containsKey(key))
{
DoubleLinkedListNode node=map.get(key);
cache.remove(node);
cache.add(node);
return node.value;
}
else return -1;
}
public void set(int key, int value) {
if(map.containsKey(key))
{
DoubleLinkedListNode node=map.get(key);
node.value=value;
cache.remove(node);
cache.add(node);
map.put(key, node);
}
else if(size==capacity)
{
map.remove(cache.head.key);
cache.remove(cache.head);
DoubleLinkedListNode node=new DoubleLinkedListNode(key, value);
cache.add(node);
map.put(key, node);
}
else
{
DoubleLinkedListNode node=new DoubleLinkedListNode(key, value);
cache.add(node);
map.put(key, node);
size++;
}
}
}
class DoubleLinkedList
{
DoubleLinkedListNode head, tail;
DoubleLinkedList()
{
head=null;tail=null;
}
void add(DoubleLinkedListNode node)
{
if(node==null)return ;
if(head==null)
{
head=node;tail=node;
}
else
{
tail.next=node;
node.prev=tail;
node.next=null;
tail=node;
}
}
void remove(DoubleLinkedListNode node)
{
if(head==null || node==null)return;
if(head==tail && node==head)
{
head=null;tail=null;return;
}
if(node==head)
{
head.next.prev=null;
head=head.next;
}
else if(node==tail)
{
tail=tail.prev;
tail.next=null;
}
else
{
node.prev.next=node.next;
node.next.prev=node.prev;
}
}
}
class DoubleLinkedListNode
{
DoubleLinkedListNode prev;
DoubleLinkedListNode next;
int key, value;
DoubleLinkedListNode(int k, int v)
{
prev=null;next=null;
key=k;value=v;
}
}
[Thoughts]
- 首先很容易想到linkedlist + hashmap
- 如果用key当timestamp,查询之后要更新list,hashmap定位不到ListNode。 所以list里面放value. 删除的list head时候要反向更新hashmap,所以listNode里还要放key。
- 双链表,给定node,删除它 O(1). 单链表需要遍历找previous
- 使用java库的LinkedHashMap, 代码如下
public class LRUCache extends LinkedHashMap<Integer, Integer>
{
int capacity;
LRUCache(int capacity)
{
super(capacity, 0.75f, true);
this.capacity=capacity;
}
int get(int key)
{
Integer value=get(key);
return value==null?-1:value.intValue();
}
void set(int key, int value)
{
put(key, value);
}
@Override
protected boolean removeEldestEntry(Entry<Integer, Integer> eldest) {
return size()>capacity;
}
}