Design a data structure that follows the constraints of a Least Recently Used (LRU) cache. Implement the LRUCache
class:
LRUCache(int capacity)
Initializes the LRU cache with positive size capacity.int get(int key)
Return the value of the key if the key exists, otherwise return -1.void put(int key, int value)
Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.The functions get
and put
must each run in O(1) average time complexity.
put
a key that already exists?
No more clarifications needed. Let’s move on to the solution.
The problem essentially requires the design of an LRU Cache with efficient get
and put
operations. To achieve O(1) average time complexity for these operations, we can use the following data structures:
We will use a combination of these two data structures:
#include <unordered_map>
using namespace std;
class LRUCache {
private:
struct DListNode {
int key;
int value;
DListNode* prev;
DListNode* next;
DListNode(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {}
};
unordered_map<int, DListNode*> cacheMap;
DListNode* head;
DListNode* tail;
int capacity;
int size;
void removeNode(DListNode* node) {
node->prev->next = node->next;
node->next->prev = node->prev;
}
void addToHead(DListNode* node) {
node->next = head->next;
node->next->prev = node;
head->next = node;
node->prev = head;
}
DListNode* removeTail() {
DListNode* node = tail->prev;
removeNode(node);
return node;
}
public:
LRUCache(int capacity) {
this->capacity = capacity;
this->size = 0;
head = new DListNode(0, 0);
tail = new DListNode(0, 0);
head->next = tail;
tail->prev = head;
}
int get(int key) {
if (cacheMap.find(key) == cacheMap.end()) {
return -1;
}
DListNode* node = cacheMap[key];
removeNode(node);
addToHead(node);
return node->value;
}
void put(int key, int value) {
if (cacheMap.find(key) != cacheMap.end()) {
DListNode* node = cacheMap[key];
node->value = value;
removeNode(node);
addToHead(node);
} else {
DListNode* newNode = new DListNode(key, value);
cacheMap[key] = newNode;
addToHead(newNode);
size++;
if (size > capacity) {
DListNode* tail = removeTail();
cacheMap.erase(tail->key);
delete tail;
size--;
}
}
}
~LRUCache() {
DListNode* current = head;
while (current) {
DListNode* next = current->next;
delete current;
current = next;
}
}
};
The solution efficiently handles the constraints and requirements of an LRU Cache.
Got blindsided by a question you didn’t expect?
Spend too much time studying?
Or simply don’t have the time to go over all 3000 questions?