题目描述
知识点
设计题(就是模拟题啦)
结果
见代码实现
实现
码前思考
- 这里我使用的是一个队列
q
来记录操作(即push
和get
)过的key
,然后使用一个map
存储key-value
对,一个map
存储在队列q
中的存在某个key
的次数,即key-count
对; - 接下来的操作就很简单了,如果加入新元素,就从队列队头取
count
为0的那个key
换出。
代码实现
哈希+队列
class LRUCache {
public:
queue<int> q;
unordered_map<int,int> kvmp; //key-value map
unordered_map<int,int> kcmp; //key-count map
//记录容量
int capacity;
//记录当前数量放入的数量
int count;
LRUCache(int capacity) {
this->capacity = capacity;
this->count = 0;
}
int get(int key) {
if(kvmp.count(key) == 0 || kcmp[key] == 0){
return -1;
}else{
kcmp[key]++; //表示该键存在次数加一
q.push(key);
return kvmp[key];
}
}
void put(int key, int value) {
if(kcmp[key] != 0){ //说明是已经有的
kvmp[key] = value;
kcmp[key]++; //表示该键存在次数加一
q.push(key);
}else if(count == capacity){ //首先检查有没有满
bool flag = false;
while(!flag){
//需要使用LRU进行筛选,筛选规则是遍历priorityqueue
int curKey =q.front();
q.pop();
//获取其次数
int curCnt = kcmp[curKey];
//如果cnt为1
if(curCnt == 1){
//printf("curKey:%d\n",curKey);
kcmp[curKey]--;
flag = true;
//需要放入
kvmp[key] = value;
kcmp[key]++;
q.push(key);
}else{
kcmp[curKey]--;
//需要继续弹出
}
}
}else{
kvmp[key] = value;
kcmp[key]++; //表示该键存在次数加一
count++;
q.push(key);
}
}
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
哈希+双向链表⭐⭐⭐⭐⭐
//使用 【hash + 双向链表】 进行解题
class LRUCache {
public:
struct Node{
int key;
int val;
Node* next;
Node* pre;
Node(){}
Node(int k,int v){
key = k;
val = v;
}
};
int cap;
int cnt;
//链表的题目使用dummyNode简直不要太爽!
Node* dummyHead;
Node* dummyEnd;
//哈希表
unordered_map<int,Node*> knmp;
LRUCache(int capacity) {
this->cap = capacity;
this->cnt = 0;
this->dummyHead = new Node();
this->dummyEnd = new Node();
dummyHead->pre = NULL;
dummyHead->next = dummyEnd;
dummyEnd->pre = dummyHead;
dummyEnd->next = NULL;
}
int get(int key) {
//首先查看缓存中是否有这个key
if(knmp.count(key) == 0){
return -1;
}else{
put(key,knmp[key]->val);
return knmp[key]->val;
}
}
void put(int key, int value) {
//如果这个key已经存在
if(knmp.count(key) != 0 ){
//需要重新调整这个key的位置,先删除它
remove(key);
//需要将它放到最前面
addToHead(key,value);
}else{
//如果这个key不在缓存中,就需要进行插入
//首先判断有没有满
if(cap == cnt){
//满了,需要删除
removeLast();
addToHead(key,value);
}else{
//未满,不需要删除,直接插到前面就好
addToHead(key,value);
cnt++; //注意cnt++呢~~
}
}
}
void remove(int key){
Node* curNode = knmp[key];
Node* pre = curNode->pre;
Node* next = curNode->next;
pre->next = next;
next->pre = pre;
knmp[key] = NULL;
return;
}
void addToHead(int key,int value){
Node* newNode = new Node(key,value);
newNode->pre = dummyHead;
newNode->next = dummyHead->next;
dummyHead->next = newNode;
newNode->next->pre = newNode;
knmp[key] = newNode;
}
void removeLast(){
//需要得到这个节点
Node* lastNode = dummyEnd->pre;
lastNode->pre->next = dummyEnd;
dummyEnd->pre = lastNode->pre;
//然后需要在哈希表中移除这个key,这个操作很重要
knmp.erase(lastNode->key);
//printf("Here\n");
}
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
码后反思
-
就是使用非常暴力的解题方法,没有什么过人之处哦。
-
之前没有考虑对
cache
中已有key
重新赋值的情况,导致答案错误,对应的解决代码如下:if(kcmp[key] != 0){ //说明是已经有的 kvmp[key] = value; kcmp[key]++; //表示该键存在次数加一 q.push(key); }
-
哈希+双向链表 应该是标准解法,这道题的意思应该是要手动实现哈希链表,哈希链表的好处就是能够同时保持快查找,快删除,快插入,有序结构,结合了哈希表和链表的特性。
-
做链表题目的时候,设置
dummyHead
和dummyEnd
简直不要太爽,能够省去好多的操作!!!