第一种解法:hash+双向链表
struct Node{
int key;
int val;
struct Node* left;
struct Node* right;
Node(int _key, int _val) : key(_key), val(_val), left(nullptr), right(nullptr){}
};//链表结点的数据格式
class LRUCache {
private:
int cap;//LRU的容量
//无序的hash表,key int, value Node* 对应的双向链表中的结点,O(1)直接找到Node
unordered_map<int, struct Node*> hash;//使用map也没问题
struct Node* head;//头指针
struct Node* tail;//尾指针
//删除指定结点p
void remove(struct Node* p)
{
p->left->right = p->right;
p->right->left = p->left;
}
//头插法,也可以采用尾插法
void insert(struct Node* p)
{
p->right = head->right;
p->left = head;
head->right->left = p;//顺序不可以搞错!!!
head->right = p;
}
public:
//构造函数,初始化
LRUCache(int capacity) {
this->cap = capacity;
head = new Node(-1, -1);
tail = new Node(-1, -1);
head->right = tail;
tail->left = head;
}
// get key
int get(int key) {
// 如果key count为0,说明不存在
if(hash.count(key) == 0) return -1;
auto p = hash[key];
remove(p);//先删除p
insert(p);//把p放在头部
return p->val;
}
void put(int key, int val) {
//key存在于hash表中,更新key的位置,更新key对应的Node结点值
if(hash.count(key) != 0)
{
auto p = hash[key];
remove(p);
insert(p);
p->val = val;
return;
}
//新插入的结点,此时LRUcache已满
if(hash.size() >= cap)
{
struct Node* p = tail->left;
remove(p);//删除尾结点
hash.erase(p->key);//删除hash表中对应的key
delete p;//记得释放
}
struct Node* tmp = new Node(key,val);//创建新的结点
hash[key] = tmp;//放入hash表
insert(tmp);//插入链表中
}
};
第二种解法:利用unordered_map本身进行匹配,实验表明,unordered_map是头插法,并且没有rbegin()迭代器,使用end()达不到想要的效果,所以每次删除数据冷的结点,需要遍历整个hash表,到第17个case通过不了
private:
int cap;
unordered_map<int, int> hash;
//使某个key的键值对放在hash表最前边
void makeRecently(int key)
{
int val = hash[key];
hash.erase(key);
hash[key] = val;
}
public:
LRUCache(int capacity) {
this->cap = capacity;
}
int get(int key) {
if(hash.find(key) == hash.end())
return -1;
makeRecently(key);
return hash[key];
}
void put(int key, int value) {
if(hash.find(key) != hash.end())
{
hash[key] = value;
makeRecently(key);
return;
}
if(hash.size() >= this->cap)
{
auto tail = hash.begin();
for(auto iter = hash.begin(); iter != hash.end(); iter++)
tail = iter;
int oldestKey = tail->first;
hash.erase(oldestKey);
//hash.erase(tail); //erase参数可以是key或者迭代器
}
hash[key] = value;
return;
}
};
两年前的解法:
class LRUCache {
public:
struct Node{
int key;
int value;
Node* left;
Node* right;
Node(int _key, int _value): key(_key),value(_value),left(NULL),right(NULL){}
}*L, *R;
int n;
unordered_map<int, Node*> hash;
void remove(Node* p)
{
p->left->right = p->right;
p->right->left = p->left;
}
void insert(Node* p)//插在头部
{
p->left = L;
p->right = L->right;
L->right->left = p;
L->right = p;
/*L->right = p;顺序千万别乱
L->right->left = p;*/
return;
}
LRUCache(int capacity) {
n = capacity;
L = new Node(-1,-1);
R = new Node(-1,-1);
L->right = R;//注意头部和尾部
R->left = L;
}
int get(int key) {
if(hash.count(key) == 0) return -1;
auto p = hash[key];
remove(p);//删除当前位置
insert(p);//放在头部
return p->value;
}
void put(int key, int value) {
if(hash.count(key) == 0)//如果不再当前lru cache中
{
if(hash.size() == n)//缓存满了
{
auto p = R->left;
if(p == NULL)
return;
remove(p);
hash.erase(p->key);
delete p;
}
//没有满,直接插入
auto p = new Node(key,value);
hash[key] = p;
insert(p);
}
else //在当前lru缓存中
{
auto p = hash[key];
p->value = value;
remove(p);
insert(p);
}
}
};