题目如下:
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.
分析如下:
经典设计题。 维持一个最近使用的元素的cache,注意这个使用包含了两种操作,set(key, value)和get(key)。
比如看一个例子。
Input: 2,[set(2,1),set(1,1),get(2),set(4,1),get(1),get(2)]
Output Expected: [1,-1,1]
使用3个数据结构:
1. structure, 把 key value打包放入结构体中存放。
2. list,维持list recent use这个数据结构,把从最近使用到最远使用的元素依次放入list的开头到结尾
3. hashmap, 保存key和它再list中的对应位置的映射。
我的代码:
我一开始没理解到LRU所指的最近的操作除了set()还有get(), 写了个vector()表达环形链表的代码,提交出错。后来修改了,是照着水中的鱼的这篇写的。
class LRUCache{
public:
struct CacheEntry {
int key;
int value;
CacheEntry(int k, int val):key(k), value(val) {}
};
LRUCache(int capacity) {
this->capacity = capacity;
}
int get(int key) {
if (key_to_pointer.find(key) != key_to_pointer.end()) {
move_to_front(key);
return key_to_pointer[key]->value;
} else {
return -1;
}
}
void set(int key, int value) {
if (key_to_pointer.find(key) != key_to_pointer.end()) {
key_to_pointer[key]->value = value;
move_to_front(key);
} else {
CacheEntry new_entry(key, value);
if(key_to_pointer.size() >= this->capacity) {
key_to_pointer.erase(list_of_entry.back().key);
list_of_entry.pop_back();
}
list_of_entry.push_front(new_entry);
key_to_pointer[key] = list_of_entry.begin();
}
return;
}
private:
unordered_map<int, list<CacheEntry>::iterator > key_to_pointer;
list<CacheEntry> list_of_entry; //因为使用了std中的list,所以可以免去在struct中增加previous 和 next的麻烦。
int capacity;
//the latest is put at head
void move_to_front(int key) {
if (key_to_pointer.size() <=1) {
//if (list_of_entry.size() <=1) { //NOTE: !!句会带来Time Limit Exceeded, 上句却不会。原因在下文。
return;
}else {
CacheEntry new_entry (key, key_to_pointer[key]->value);
list_of_entry.erase(key_to_pointer[key]);
list_of_entry.push_front(new_entry);
key_to_pointer[key]=list_of_entry.begin();
return;
}
}
};
小结扩展:
1 在一些平台上,list.size()的时间复杂度是O(N), 不是O(1)。所以上面的 if (list_of_entry.size() <=1) {会带来超时。 具体哪些平台这里有讨论。
参考资料:
http://fisherlei.blogspot.com/2013/11/leetcode-lru-cache-solution.html