题目地址:
https://leetcode.com/problems/lru-cache/
设计一个数据结构作为Least Recently Used Cache。它可以实现下面的操作:
1、get(key),得到key对应的value(题目保证得到的value一定是正数)。如果对应的key不存在,则返回
−
1
−1
−1;
2、set(key, value),如果cache里不存在这样的key,就添加进去;否则就将key对应的value设成参数value;
3、cache有容量限制,当存储的数据超过容量限制的时候,要按照最近一次使用的时间最早的顺序将其删除。”使用“包括get和set。
可以用双向链表 + 哈希表的方法来做。链表的作用是存储key和value,哈希表的作用是存储key和key对应的node。
具体的方法是,如果要get某个值时,先去哈希表里查这个值有没有,没有直接返回-1,否则得到这个key对应的节点,然后删除掉那个对应的节点,接着在链表头新建一个对应节点的拷贝,这样就达到了“最近get过的节点都在头,最近没get过的节点都在链表尾”的效果,一旦到了capacity,就直接把链表尾部节点删掉即可。
如果要put某个值时,做法和get类似,也是要先查一下有没有那个key,没有的话直接在表头加,否则也是把中间那个node删掉再在表头新建一个拷贝。
注:
链表里可以只放value不放key吗?答案是不可以。因为在超过capacity的时候需要删除首个结点的时候,只知道其value无法知道其key,就无法在哈希表里删除对应的key。
代码如下:
class LRUCache {
public:
struct ListNode {
ListNode *prev, *next;
int key, val;
ListNode(int key, int val) {
this->key = key;
this->val = val;
prev = next = nullptr;
}
};
using node_p = ListNode*;
node_p head, tail;
node_p nn(int key, int val) { return new ListNode(key, val); }
unordered_map<int, node_p> mp;
int sz, cap;
LRUCache(int capacity) {
cap = capacity;
sz = 0;
head = nn(0, 0), tail = nn(0, 0);
head->next = tail, tail->prev = head;
}
node_p delink(node_p node) {
if (node->next) node->next->prev = node->prev;
if (node->prev) node->prev->next = node->next;
return node;
}
void move_to_head(node_p node) {
delink(node);
node->next = head->next, node->prev = head;
head->next = node, node->next->prev = node;
}
int get(int key) {
if (!mp.count(key)) return -1;
auto node = mp[key];
move_to_head(node);
return node->val;
}
void put(int key, int value) {
if (mp.count(key)) {
auto node = mp[key];
node->val = value;
move_to_head(node);
} else {
sz++;
move_to_head(nn(key, value));
mp[key] = head->next;
if (sz > cap) {
mp.erase(delink(tail->prev)->key);
sz--;
}
}
}
};
所有操作时间复杂度 O ( 1 ) O(1) O(1),空间 O ( k ) O(k) O(k), k k k是容量。