
【题目】:146. LRU 缓存
LRU:最近最少未使用,很少被请求的数据才会被淘汰掉
本质:让不经常访问的数据往下排,经常访问的数据往上排。

这样会导致:冷门数据在最下边,热门数据在最上边。
如果访问的数据缓存中没有
且缓存已经满了
:把最下边的数据淘汰掉,再把刚访问的数据放到上边(换页)
分析:
- 选用什么数据结构?
数组:添加一个节点,所有节点都要往后移动,时间复杂度O(n)
链表:添加节点、删除节点只需要改变节点指向,时间复杂度O(1)。只需要改变指针的指向即可。由于不仅要直到节点的下一位,还需要直到节点的上一位,所以使用双向链表
。
- 怎么找到链表的某个节点?
正常查询链表的某个节点,需要逐个遍历链表元素,时间复杂度O(n)。那有没有办法优化到O(1)的时间复杂度呢?
hashMap的查询时间复杂度是O(1),可以用hashMap
来存储链表节点。
最后选择数据结构如下:

- 双向链表数据结构
class Node { public: int key; int value; Node *pre; Node *next; Node(int key, int value) { this->key = key; this->value = value; this->pre = nullptr; this->next = nullptr; } Node() { this->key = 0; this->value = 0; this->pre = nullptr; this->next = nullptr; } };
|
class LRUCache { public: int capacity; int size;
Node *head; Node *tail;
unordered_map<int, Node*> mp;
LRUCache(int capacity) { this->capacity = capacity; this->size = 0; head = new Node(); tail = new Node(); head->next = tail; tail->pre = head; } int get(int key) { if(mp.find(key) == mp.end()) { return -1; } Node *node = mp[key]; deleteNodeAndInsertHead(node); return node->value; } void put(int key, int value) { if(mp.find(key) == mp.end()) { if(size == capacity) { Node *delNode = tail->pre; deleteNode(delNode); mp.erase(delNode->key); }else { ++size; } Node *node = new Node(key, value); insertHead(node); mp[key] = node; }else { Node *node = mp[key]; node->value = value; mp[key] = node; deleteNodeAndInsertHead(node); } } private: void deleteNode(Node *node) { node->pre->next = node->next; node->next->pre = node->pre; } void insertHead(Node *node) { head->next->pre = node; node->next = head->next; node->pre = head; head->next = node; } void deleteNodeAndInsertHead(Node *node) { deleteNode(node); insertHead(node); } };
|