转载
作者:鱼与海洋
出处:http://www.cnblogs.com/joannacode/p/5998949.html
leetcode题目地址
https://leetcode.com/problems/lru-cache/
题目描述
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(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.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // returns 1
cache.put(3, 3); // evicts key 2
cache.get(2); // returns -1 (not found)
cache.put(4, 4); // evicts key 1
cache.get(1); // returns -1 (not found)
cache.get(3); // returns 3
cache.get(4); // returns 4
Subscribe to see which companies asked this question.
ac代码
采用 双向链表 + map(效率还是不错的 map进一步可用成unordered_map)
- 数据结构设计
typedef struct node{
int key;
int val;
struct node* pre;
struct node* next;
node(int _key = -1, int _val = -1)
{
key = _key;
val = _val;
pre = NULL;
next = NULL;
}
}DNode;
class LRUCache
{
public:
LRUCache(int _capacity) {
capacity = _capacity;
size = 0;
head = new DNode();
tail = new DNode();
head->next = tail;
tail->pre = head;
mp.clear();
}
int get(int key) {
map<int,DNode*>::iterator it= mp.find(key);
if(it == mp.end()) //如果在Cache中不存在该key, 则返回-1
{
return -1;
}
else
{
DNode* t = it->second;
// 把 t分离出来,然后将t插入到头部位置
t->pre->next = t->next;
t->next->pre = t->pre;
t->pre = head;
t->next = head->next;
head->next = t;
t->next->pre = t;
return t->val;
}
}
void put(int key, int value) {
map<int,DNode*>::iterator it= mp.find(key);
if(it == mp.end()) //如果在Cache中不存在该key, 则返回-1
{
if(size == capacity) //如果双向链表容量已满即缓存容量已满,则将最近不使用的节点即链表最后一个数据节点删除
{
// 删除最后一个
DNode *tmp = tail->pre;
tail->pre->pre->next = tail;
tail->pre = tmp->pre;
mp.erase(tmp->key);
delete tmp;
size--;
}
//把新节点插入到head的后面 更新map
DNode *newNode = new DNode(key, value);
newNode->pre = head;
newNode->next = head->next;
head->next = newNode;
newNode->next->pre = newNode;
mp[key] = newNode;//在hashtable添加key对应的表项
size++;//链表节点数++
}else{ // 当前put的可以存在,需要更新value
DNode* t = it->second;
// 把 t分离出来,然后将t插入到头部位置
t->pre->next = t->next;
t->next->pre = t->pre;
t->val = value; //**
t->pre = head;
t->next = head->next;
head->next = t;
t->next->pre = t;
return;
}
}
private:
int capacity;
int size;
DNode* head;
DNode* tail;
map<int,DNode*> mp;
};
ac2 (C++ list + map)
考虑到c++ list本身就是个 双向链表,可以直接采用list(效率会比较差,不过能ac)
class LRUCache
{
public:
LRUCache(int _capacity) {
capacity = _capacity;
size = 0;
cachelist.clear();
mp.clear();
}
int get(int key) {
map<int,pair<int,int>>::iterator it= mp.find(key);
if(it == mp.end()) //如果在Cache中不存在该key, 则返回-1
{
return -1;
}
else
{
pair<int,int> t = it->second;
pair<int,int> newPair(t.first, t.second);
cachelist.remove(t);
cachelist.push_front(newPair);
return newPair.second;
}
}
void put(int key, int value) {
map<int,pair<int,int>>::iterator it= mp.find(key);
if(it == mp.end()) //如果在Cache中不存在该key, 则返回-1
{
if(size == capacity) //如果双向链表容量已满即缓存容量已满,则将最近不使用的节点即链表最后一个数据节点删除
{
pair<int,int> tmp = cachelist.back();
cachelist.pop_back();
mp.erase(tmp.first);
size--;
}
pair<int,int> newPair(key,value);
cachelist.push_front(newPair);
mp[key] = newPair;
size++;//链表节点数++
}else{ // 当前put的可以存在,需要更新value
pair<int,int> t = it->second;
pair<int,int> newPair(key,value);
cachelist.remove(t);
cachelist.push_front(newPair);
mp[t.first] = newPair;
return;
}
}
private:
int capacity;
int size;
list<pair<int,int>> cachelist;
map<int, pair<int,int>> mp;
};
ac3
按照数据结构图的思想来写代码会容易很多
typedef struct node
{
int key;
int val;
struct node* next;
struct node* pre;
node(int _key = -1, int _val = -1){
key = _key;
val = _val;
next = NULL;
pre = NULL;
}
}Dnode;
class LRUCache {
public:
int size;
int cap;
Dnode* head;
Dnode* tail;
map<int, Dnode*> mp;
LRUCache(int capacity) {
size = 0;
cap =capacity;
head = new Dnode;
tail = new Dnode;
head->next = tail;
tail->pre = head;
}
int get(int key) {
if(mp.count(key) == 0)
return -1;
Dnode* oldPos = mp[key];
int val = oldPos->val; //要返回的val
Dnode* oldpre = oldPos->pre;
oldPos->next->pre = oldpre;
oldpre->next = oldPos->next;
delete oldPos;
mp.erase(key);
Dnode* newPos = new Dnode(key,val);
head->next->pre = newPos;
newPos->next = head->next;
newPos->pre = head;
head->next = newPos;
mp[key] = newPos;
return val;
}
void put(int key, int value) {
if(cap <= 0)
return;
int storeVal = get(key);
if(storeVal != -1)
{
head->next->val = value;
mp[key]->val = value;
return;
}
if(size == cap)
{
Dnode* delNode = tail->pre;
int delKey = delNode->key;
Dnode* delpre = tail->pre->pre;
delpre->next = tail;
tail->pre= delpre;
delete delNode;
mp.erase(delKey);
size --;
}
Dnode* newPos = new Dnode(key,value);
head->next->pre = newPos;
newPos->next = head->next;
newPos->pre = head;
head->next = newPos;
mp[key] = newPos;
size ++;
}
};
上面的代码,改进一下get方法(可以优化一点运行时间)
int get(int key) {
if(mp.count(key) == 0)
return -1;
Dnode* oldPos = mp[key];
int val = oldPos->val; //要返回的val
Dnode* oldpre = oldPos->pre;
oldPos->next->pre = oldpre;
oldpre->next = oldPos->next;
//delete oldPos;
//mp.erase(key);
//Dnode* newPos = new Dnode(key,val);
Dnode* newPos = oldPos; //直接更新
head->next->pre = newPos;
newPos->next = head->next;
newPos->pre = head;
head->next = newPos;
mp[key] = newPos;// 直接更新
return val;
}