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.
http://blog.csdn.net/dazhi_100/article/details/44201051
http://gogole.iteye.com/blog/692103
可以用Java自带的LinkedHashMap,重写removeEldestEntry方法实现触发删除最不常用的条件,在构造器的第三个参数设置为true实现按照最不常用的方式排序
public class LRUCache {
LinkedHashMap<Integer, Integer> map;
int capacity;
public CopyOfLRUCache(int capacity) {
this.capacity = capacity;
map = new LinkedHashMap<Integer, Integer>(256, 0.75f, true){
private static final long serialVersionUID = 1L;
@Override
protected boolean removeEldestEntry(Entry<Integer, Integer> eldest) {
return size() > CopyOfLRUCache.this.capacity;
}
};
}
public int get(int key) {
return map.containsKey(key) ? map.get(key) : -1;
}
public void set(int key, int value) {
map.put(key, value);
}
}
在网上看了一下,可以用HashMap + 双向链表 实现。在Discuss看到有个大神级的答案:
The problem can be solved with a hashtable that keeps track of the keys and its values in the double linked list. One interesting property about double linked list is that the node can remove itself without other reference. In addition, it takes constant time to add and remove nodes from the head or tail.
One particularity about the double linked list that I implemented is that I create a pseudo head and tail to mark the boundary, so that we don't need to check the NULL node during the update. This makes the code more concise and clean, and also it is good for the performance as well.
import java.util.HashMap;
class DLinkedNode {
int key, value;
DLinkedNode pre, post;
}
public class LRUCache {
HashMap<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();
int capacity;
DLinkedNode head, tail;
// Always add the new node right after head;
private void addNode(DLinkedNode node) {
node.pre = head;
node.post = head.post;
head.post.pre = node;
head.post = node;
}
// Remove an existing node from the linked list.
private void removeNode(DLinkedNode node) {
DLinkedNode pre = node.pre;
DLinkedNode post = node.post;
pre.post = post;
post.pre = pre;
}
// Move certain node in between to the head.
private void moveToHead(DLinkedNode node) {
this.removeNode(node);
this.addNode(node);
}
// pop the current tail.
private DLinkedNode popTail() {
DLinkedNode res = tail.pre;
removeNode(res);
return res;
}
public LRUCache(int capacity) {
this.capacity = capacity;
head = new DLinkedNode();
tail = new DLinkedNode();
head.post = tail;
tail.pre = head;
head.pre = null;
tail.post = null;
}
public int get(int key) {
if(!cache.containsKey(key)) return -1;
DLinkedNode node = cache.get(key);
moveToHead(node);
return node.value;
}
public void set(int key, int value) {
if(cache.containsKey(key)) {
DLinkedNode target = cache.get(key);
target.value = value;
moveToHead(target);
} else {
if(cache.size() == capacity) {
DLinkedNode tail = popTail();
cache.remove(tail.key);
}
DLinkedNode newNode = new DLinkedNode();
newNode.key = key;
newNode.value = value;
cache.put(key, newNode);
addNode(newNode);
}
}
}
用Python
1. OrderedDict应该内置了双端队列的实现
2. OrderedDict.popitem(last=True)
from collections import OrderedDict
class LRUCache(object):
def __init__(self, capacity):
"""
:type capacity: int
"""
self.d = OrderedDict()
self.capacity = capacity
def get(self, key):
"""
:type key: int
:rtype: int
"""
if key not in self.d: return -1
val = self.d[key]
del self.d[key]
self.d[key]=val
return val
def put(self, key, value):
"""
:type key: int
:type value: int
:rtype: void
"""
if key in self.d: del self.d[key]
if len(self.d)==self.capacity:
self.d.popitem(False)
self.d[key]=value
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)