LRU Cache
Problem Statement - link #
Design a data structure that works like a LRU Cache. Here cap
denotes the capacity of the cache and Q
denotes the number of queries. Query can be of two types:
SET x y
: sets the value of the keyx
with valuey
GET x
: gets the key ofx
if present else returns-1
.
The LRUCache class has two methods get()
and set()
which are defined as follows.
get(key)
: returns the value of thekey
if it already exists in the cache otherwise returns-1
.set(key, value)
: if thekey
is already present, update its value. If not present, add the key-value pair to the cache. If the cache reaches its capacity it should invalidate the least recently used item before inserting the new item.- In the constructor of the class the capacity of the cache should be intitialized.
Your Task: You don’t need to read input or print anything . Complete the constructor and get(), set()
methods of the class LRUcache
.
Expected Time Complexity: O(1)
for both get() and set() Expected Auxiliary Space: O(1)
for both get() and set() (Although, you may use extra space for cache storage and implementation purposes).
Examples #
Example 1:
Input:
cap = 2
Q = 2
Queries = SET 1 2 GET 1
Output: 2
Explanation:
Cache Size = 2
SET 1 2 GET 1
SET 1 2 : 1 -> 2
GET 1 : Print the value corresponding
to Key 1, ie 2.
Example 2:
Input:
cap = 2
Q = 8
Queries = SET 1 2 SET 2 3 SET 1 5
SET 4 5 SET 6 7 GET 4 SET 1 2 GET 3
Output: 5 -1
Explanation:
Cache Size = 2
SET 1 2 : 1 -> 2
SET 2 3 : 1 -> 2, 2 -> 3 (the most recently
used one is kept at the rightmost position)
SET 1 5 : 2 -> 3, 1 -> 5
SET 4 5 : 1 -> 5, 4 -> 5 (Cache size is 2, hence
we delete the least recently used key-value pair)
SET 6 7 : 4 -> 5, 6 -> 7
GET 4 : Prints 5 (The cache now looks like
6 -> 7, 4->5)
SET 1 2 : 4 -> 5, 1 -> 2
(Cache size is 2, hence we delete the least
recently used key-value pair)
GET 3 : No key value pair having
key = 3. Hence, -1 is printed.
Constraints #
1 <= cap <= 1000
1 <= Q <= 100000
1 <= key,value <= 1000
Solutions #
class LRUCache
{
private:
struct Node
{
int key;
int value;
Node* prev;
Node* next;
Node(int key1, int value1)
{
key = key1;
value = value1;
}
};
public:
int capacity;
int size;
Node* head;
Node* tail;
unordered_map<int, Node*> map;
//Constructor for initializing the cache capacity with the given value.
LRUCache(int capacity)
{
this->capacity = capacity;
this->size = 0;
this->head = NULL;
this->tail = NULL;
}
// delete a node
void delete_node(Node* node) {
if (node->prev != NULL) {
node->prev->next = node->next;
}
if (node->next != NULL) {
node->next->prev = node->prev;
}
if (node == head) {
head = node->next;
}
if (node == tail) {
tail = node->prev;
}
delete node;
}
// insert a node at the beginning of the list
void insert(Node* node) {
if (head == NULL) {
head = node;
tail = node;
} else {
node->next = head;
head->prev = node;
head = node;
}
}
// move a node to the beginning of the list
void move_to_beginning(Node* node) {
if (node == head) {
return;
}
if (node->prev != NULL) {
node->prev->next = node->next;
}
if (node->next != NULL) {
node->next->prev = node->prev;
}
if (node == tail) {
tail = node->prev;
}
node->next = head;
node->prev = NULL;
head->prev = node;
head = node;
}
//Function to return value corresponding to the key.
int get(int key)
{
// your code here
if (map.find(key) == map.end())
{
return -1;
}
Node* node = map[key];
move_to_beginning(node);
return node->value;
}
//Function for storing key-value pair.
void set(int key, int value)
{
// your code here
if (map.find(key) == map.end())
{
if (size == capacity)
{
map.erase(tail->key);
delete_node(tail);
size--;
}
Node* node = new Node(key, value);
insert(node);
map[key] = node;
size++;
}
else
{
Node* node = map[key];
node->value = value;
move_to_beginning(node);
}
}
};