運用你所掌握的數據結構,設計和實現一個 LRU (最近最少使用) 緩存機制 。
實現 LRUCache 類:node
LRUCache(int capacity) 以正整數做爲容量 capacity 初始化 LRU 緩存
int get(int key) 若是關鍵字 key 存在於緩存中,則返回關鍵字的值,不然返回 -1 。
void put(int key, int value) 若是關鍵字已經存在,則變動其數據值;若是關鍵字不存在,則插入該組「關鍵字-值」。當緩存容量達到上限時,它應該在寫入新數據以前刪除最久未使用的數據值,從而爲新的數據值留出空間。
緩存
示例:數據結構
輸入 ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] 輸出 [null, null, null, 1, null, -1, null, -1, 3, 4] 解釋 LRUCache lRUCache = new LRUCache(2); lRUCache.put(1, 1); // 緩存是 {1=1} lRUCache.put(2, 2); // 緩存是 {1=1, 2=2} lRUCache.get(1); // 返回 1 lRUCache.put(3, 3); // 該操做會使得關鍵字 2 做廢,緩存是 {1=1, 3=3} lRUCache.get(2); // 返回 -1 (未找到) lRUCache.put(4, 4); // 該操做會使得關鍵字 1 做廢,緩存是 {4=4, 3=3} lRUCache.get(1); // 返回 -1 (未找到) lRUCache.get(3); // 返回 3 lRUCache.get(4); // 返回 4
這題有幾個須要注意的點:this
爲了保證get和put都知足O(1)的時間複雜度,又因爲是根據最近是否訪問來決定淘汰順序,最直觀的方案是使用隊列。但隊列有個致命缺陷——只能操做隊頭元素和隊尾元素,這就意味着get()操做時十分麻煩。
另外一個經典的思路是雙鏈表+hashmap,雙鏈表的插入刪除時間複雜度都是O(1),而hashmap指針取出結點指針保證了get()的時間複雜度爲O(1)。
另外有幾點須要注意:設計
struct DLinkNode { int key, value; DLinkNode *prev, *next; DLinkNode(): key(0), value(0), prev(nullptr), next(nullptr) {} DLinkNode(int _key, int _value): key(_key), value(_value), prev(nullptr), next(nullptr) {} }; class LRUCache { public: LRUCache(int capacity) { this->cap = capacity; this->len = 0; tail = new DLinkNode; head = new DLinkNode; tail -> prev = head; head -> next = tail; } int get(int key) { if(hashmap.count(key)) { DLinkNode* node = hashmap[key]; movetoTail(node); return node -> value; } return -1; } void put(int key, int value) { if(!hashmap.count(key)) { DLinkNode* node = new DLinkNode(key, value); addNode(node); hashmap[key] = node; len++; if(len > cap) { removeNode(head -> next); len--; } } else { hashmap[key] -> value = value; movetoTail(hashmap[key]); } } void movetoTail(DLinkNode* node) { node -> prev -> next = node -> next; node -> next -> prev = node -> prev; tail -> prev -> next = node; node -> prev = tail -> prev; tail -> prev = node; node -> next = tail; } void addNode(DLinkNode* node) { tail -> prev -> next = node; node -> prev = tail -> prev; node -> next = tail; tail -> prev = node; } void removeNode(DLinkNode* node) { node -> prev -> next = node -> next; node -> next -> prev = node -> prev; hashmap.erase(node->key); delete node; } private: unordered_map<int, DLinkNode*> hashmap; DLinkNode *head, *tail; int cap; int len; };