2014.2.13 18:15
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get
and set
.
get(key)
- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.set(key, value)
- Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
Solution:
My LRU cache is made up of two parts, a hash table and a double-linked list.
Hash table provides O(1) access to every element in the cache. Double-linked list allows you to move a node to the head or to the tail in O(1) time, although you'll need O(n) time locating this node. With their combiantion, both process can reach O(1) complexity.
The double-linked list is handwritten, while the hash table is unordered_map from new STL.
It's quite easy to make mistake on linked list, especially when it is double-linked.
Whenever set() or get() is called, the node visitied or created should be put on the front of the list.
Time complexity is O(1) for both set() and get(), linked list and hashing both use O(n) space.
Accepted code:
1 // 1WA, 1AC, double-linked list + unordered_map 2 #include <unordered_map> 3 using namespace std; 4 5 typedef struct DoubleLinkedListNode{ 6 public: 7 int key; 8 int value; 9 struct DoubleLinkedListNode *left; 10 struct DoubleLinkedListNode *right; 11 DoubleLinkedListNode(int _key = 0, int _value = 0): key(_key), value(_value), left(nullptr), right(nullptr) {} 12 }DoubleLinkedListNode; 13 14 class LRUCache{ 15 public: 16 LRUCache(int capacity) { 17 this->capacity = capacity; 18 this->size = 0; 19 this->head = this->tail = nullptr; 20 this->hash_table.clear(); 21 } 22 23 int get(int key) { 24 if (size == 0) { 25 // the LRU cache is empty. 26 return KEY_NOT_FOUND; 27 } 28 29 unordered_map<int, DoubleLinkedListNode *>::iterator mit; 30 31 mit = hash_table.find(key); 32 if (mit != hash_table.end()) { 33 // the key exists in the cache. 34 DoubleLinkedListNode *ptr = mit->second; 35 if (ptr == head) { 36 // do nothing 37 } else if (ptr == tail) { 38 // ptr is the tail node. 39 tail = ptr->left; 40 tail->right = nullptr; 41 ptr->left = nullptr; 42 ptr->right = head; 43 head->left = ptr; 44 head = ptr; 45 } else { 46 // ptr is at middle of the list. 47 DoubleLinkedListNode *ptr1, *ptr2; 48 ptr1 = ptr->left; 49 ptr2 = ptr->right; 50 ptr1->right = ptr2; 51 ptr2->left = ptr1; 52 ptr->left = nullptr; 53 ptr->right = head; 54 head->left = ptr; 55 head = ptr; 56 } 57 return ptr->value; 58 } else { 59 // key not found. 60 return KEY_NOT_FOUND; 61 } 62 } 63 64 void set(int key, int value) { 65 if (capacity == 0) { 66 // no room to place anything. 67 return; 68 } 69 70 unordered_map<int, DoubleLinkedListNode *>::iterator mit; 71 mit = hash_table.find(key); 72 if (mit != hash_table.end()) { 73 // the key exists in the cache. 74 DoubleLinkedListNode *ptr = mit->second; 75 if (ptr == head) { 76 // do nothing 77 } else if (ptr == tail) { 78 // ptr is the tail node. 79 tail = ptr->left; 80 tail->right = nullptr; 81 ptr->left = nullptr; 82 ptr->right = head; 83 head->left = ptr; 84 head = ptr; 85 } else { 86 // ptr is at middle of the list. 87 DoubleLinkedListNode *ptr1, *ptr2; 88 ptr1 = ptr->left; 89 ptr2 = ptr->right; 90 ptr1->right = ptr2; 91 ptr2->left = ptr1; 92 ptr->left = nullptr; 93 ptr->right = head; 94 head->left = ptr; 95 head = ptr; 96 } 97 ptr->value = value; 98 } else { 99 DoubleLinkedListNode *ptr = nullptr; 100 if (size < capacity) { 101 // still some space left. 102 // put the new item at front, not rear. 103 ptr = new DoubleLinkedListNode(key, value); 104 if (head != nullptr) { 105 head->left = ptr; 106 ptr->right = head; 107 } else { 108 tail = ptr; 109 } 110 head = ptr; 111 hash_table[key] = ptr; 112 ++size; 113 } else { 114 // capacity is reached. 115 ptr = tail; 116 hash_table.erase(tail->key); 117 ptr->key = key; 118 ptr->value = value; 119 if (head != tail) { 120 tail = ptr->left; 121 tail->right = nullptr; 122 ptr->left = nullptr; 123 ptr->right = head; 124 head->left = ptr; 125 head = ptr; 126 } 127 hash_table[key] = ptr; 128 } 129 } 130 } 131 private: 132 static const int KEY_NOT_FOUND = -1; 133 int capacity; 134 int size; 135 DoubleLinkedListNode *head; 136 DoubleLinkedListNode *tail; 137 unordered_map<int, DoubleLinkedListNode *> hash_table; 138 };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)