题目描述
设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥已经存在,则变更其数据值;如果密钥不存在,则插入该组「密钥/数据值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
题解
哈希表查找快,但是数据无固定顺序;链表有顺序之分,插入删除快,但是查找慢。所以结合一下,形成一种新的数据结构:哈希链表。LRU 缓存算法的核心数据结构就是哈希链表,双向链表和哈希表的结合体。
删除一个节点不光要得到该节点本身的指针,也需要操作其前驱节点的指针,而双向链表才能支持直接查找前驱,保证操作的时间复杂度 O(1)O(1)。
当缓存容量已满,我们不仅仅要删除最后一个 Node 节点,还要把 map 中映射到该节点的 key 同时删除,而这个 key 只能由 Node 得到。如果 Node 结构中只存储 val,那么我们就无法得知 key 是什么,就无法删除 map 中的键,造成错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class LRUCache { private: int cap; list<pair<int, int>> cache; unordered_map<int, list<pair<int, int>>::iterator> map; public: LRUCache(int capacity){ this->cap = capacity; } int get(int key){ auto it = map.find(key); if (it == map.end())return -1; pair<int, int> kv = *(map[key]); cache.erase(map[key]); cache.push_front(kv); map[key] = cache.begin(); return kv.second; } void put(int key, int value) { auto it = map.find(key); if (it != map.end()){ pair<int, int> kv = *(map[key]); kv.second = value; cache.erase(map[key]); cache.push_front(kv); map[key] = cache.begin(); } else{ if (map.size() == cap){ auto lastPair = cache.back(); map.erase(lastPair.first); cache.pop_back(); } cache.push_front(make_pair(key, value)); map[key] = cache.begin(); } } };
|
链接:https://leetcode-cn.com/problems/lru-cache/solution/lru-ce-lue-xiang-jie-he-shi-xian-by-labuladong/
之后要准备复现论文了,刷题的事情就暂且停一停吧。