赞
踩
以146. LRU为例,题目如下:
可以定义链表节点对应缓冲块,这样就可以用双向链表保存当前的缓存块,每次加入、更新或查找缓存块都会使对应节点移动至链表头,每次需要替换出缓存块时将链尾节点(最久未使用)移除,使用链表的好处是定位到对应节点后,再进行插入或删除操作的时间复杂度都是 O ( 1 ) O(1) O(1)的,但定位链表节点就比较慢,所有可以使用哈希表记录缓存块的键对应的链表节点,这样定位链表节点的时间复杂度就是近似 O ( 1 ) O(1) O(1)的。在操作过程我们维护哈希表和链表(链表头尾节点),这样就可以实现O(1)的平均时间复杂度的 g e t get get和 p u t put put方法。实现过程中可以封装两个基本的方法:1) e m p l a c e _ f r o n t emplace\_front emplace_front: 将新节点插入链表头同时更新哈希表, 2) u p d a t e update update: 更新或访问链表中的节点:先将原节点从链表中删除,再将新节点插入链表头,同时更新哈希表node。
双向链表节点类:
class Node {
public:
int k, v;//键,值
Node *prev, *next;//前驱节点,后继节点
Node(int key = -1, int val = -1, Node *prev_ = nullptr, Node *next_ = nullptr) : k(key), v(val), prev(prev_), next(next_) {}
};
LRU实现:
class LRUCache { public: LRUCache(int capacity) { n = capacity; cnt = 0; head = new Node(); tail = head; } int get(int key) { if (!node.count(key)) return -1; update(key); return node[key]->v; } void put(int key, int value) { if (node.count(key)) { update(key, value); return; } if (cnt++ == n) { cnt--; node.erase(tail->k); Node *tail0 = tail; tail = tail->prev; tail->next = nullptr; delete tail0; } emplace_front(key, value); } private: int n; Node *head, *tail;//链表头尾节点 unordered_map<int, Node *> node;//键到链表节点的映射 int cnt;//节点数 void emplace_front(int key, int value) {//将(key,value)插入链表头, 同时更新哈希表node Node *t = new Node(key, value, head, head->next); if (head == tail)//可能需要更新tail节点 tail = t; if (head->next) head->next->prev = t; head->next = t; node[key] = t;//更新哈希表 } void update(int key, int val = -1) {//更新或访问(key,val): 先将(key,val)从链表中删除, 再将新的(key,val)插入链表头, 同时更新哈希表node Node *x = node[key]; if (val != -1)//更新val x->v = val; if (x == tail) tail = tail->prev; x->prev->next = x->next; if (x->next) x->next->prev = x->prev; emplace_front(x->k, x->v); delete x; } };
使用list同时用list的迭代器模拟链表节点,这样的好处就是不用手动维护链表的尾节点,同时list有 e m p l a c e _ f r o n t emplace\_front emplace_front、 p o p _ b a c k pop\_back pop_back等方法,就不用再去实现一遍,所有通过list迭代器模拟链表节点来实现比自定义链表节点实现会更简洁一些。
class LRUCache { public: LRUCache(int capacity) { n = capacity; } int get(int key) { if (!node.count(key)) return -1; update(key); return node[key]->second; } void put(int key, int value) { if (node.count(key)) { update(key, value); return; } if (li.size() == n) { node.erase(li.rbegin()->first); li.pop_back(); } li.emplace_front(key, value); node[key] = li.begin(); } private: int n; list<pair<int, int>> li;//链表 unordered_map<int, list<pair<int, int>>::iterator> node;//键到链表节点的映射 void update(int key, int val = -1) {//更新或访问(key,val): 先将(key,val)从链表中删除, 再将新的(key,val)插入链表头, 同时更新哈希表node auto x = *node[key]; if (val != -1) x.second = val; li.erase(node[key]); li.push_front(x); node[key] = li.begin(); } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。