Code360 powered by Coding Ninjas X Naukri.com. Code360 powered by Coding Ninjas X Naukri.com

LRU Cache Implementation

Moderate
0/80
Average time to solve is 25m
profile
Contributed by
92 upvotes
Asked in companies
ZomatoQualcommOracle

Problem statement

Design and implement a data structure for Least Recently Used (LRU) cache to support the following operations:

1. get(key) - Return the value of the key if the key exists in the cache, otherwise return -1.

2. put(key, value), Insert the value in the cache if the key is not already present or update the value of the given key if the key is already present. When the cache reaches its capacity, it should invalidate the least recently used item before inserting the new item.
You will be given ‘Q’ queries. Each query will belong to one of these two types:
Type 0: for get(key) operation.
Type 1: for put(key, value) operation.
Note :
1. The cache is initialized with a capacity (the maximum number of unique keys it can hold at a time).

2. Access to an item or key is defined as a get or a put operation on the key. The least recently used key is the one with the oldest access time.
Detailed explanation ( Input/output format, Notes, Images )
Input Format :
The first line of input contains two space-separated integers 'C' and 'Q', denoting the capacity of the cache and the number of operations to be performed respectively.

The next Q lines contain operations, one per line. Each operation starts with an integer which represents the type of operation. 

If it is 0, then it is of the first type and is followed by one integer key. 

If it is 1, it is of the second type and is followed by two space-separated integers key and value(in this order). 
Output Format :
For each operation of type 0, print an integer on a single line, denoting the value of the key if the key exists, otherwise -1.
Note :
You don't need to print anything, it has already been taken care of. Just implement the given function.
Constraints :
1 <= C <= 10^4
1 <= Q <= 10^5
1 <= key, value <= 10^9

Time Limit: 1 sec
Sample Input 1 :
3 11
1 1 1
1 2 2
1 3 3
1 4 5
0 3
0 1
0 4
1 2 3
0 1
0 3
0 2
Sample Output 1 :
3
-1
5
-1
3
3
Explanation to Sample Input 1 :

alt-text

Initializing a cache of capacity 3, LRUCache cache = new LRUCache(3);
Then each operation is performed as shown in the above figure.
cache.put(1,1)
cache.put(2,2)
cache.put(3,3)
cache.put(4,5)
cache.get(3)      // returns 3
cache.get(1)      // returns -1
cache.get(2)      // returns 2
cache.put(5,5)
cache.get(4)      // returns -1
cache.get(3)      // returns 3
Sample Input 2 :
2 6
1 1 1
1 2 2
0 2
1 3 3
0 3
0 1
Sample Output 2 :
2
3
-1
Hint

Use an array to store the keys and maintain the access time after each get or put operation.

Approaches (2)
Array Approach

We will use an array of type Pair<key, value> to implement our LRU Cache where the larger the index is, the more recently the key is used. Means, the 0th index denotes the least recently used pair, and the last index denotes the most recently used pair.

 

The key will be considered as accessed if we try to perform any operation on it. So while performing the get operation on a key, we will do a linear search, if the key found in the cache at an index id we will left shift all keys starting from id+1 in the cache by one and put the key at the end (marking it as the most recently used key in the cache). 

 

Similarly, while performing the put operation on a key, we will do a linear search, if the key found at index equals to id, we will shift left all keys starting from id+1 in the cache by one and put the key at the end. Otherwise, we will check the current size of the cache. If the size equals capacity, we will remove the first(0th) key from the cache by doing the left shift on all the keys by one. Now we can simply insert the key at the end.

 

size: denotes the current size of the cache.

capacity: denotes the maximum keys cache can hold at one time.

cache: denotes the array of type pair to store key-value pairs.

Pair: Pair type will store these values, key, value.

 

Algorithm

 

This method will return the index of the key if it exists in the cache, otherwise -1.

 

getIndex(int key):

  • For all the pairs in the cache, from i = 0 to size - 1.
    • If currentPair->key == key, return i.
  • Return -1, as the given key does not exist in the cache.

This method will shift left all the pairs starting from the start index by 1.

 

leftShift(int start):

  • If start == size, no pair exists to shift, return.
  • For all pairs in tha cache, from i = start to size - 1,
    • cache[i - 1] = cache[i]

 

int get(key):

  • ID = getIndex(key).
  • If ID == -1, the key does not exist in the cache, return -1.
  • Get the pair at index = ID, let it pair.
  • leftShift(ID + 1).
  • cache[size - 1] = pair
  • Return pair->value.

 

void put(key, value):

  • ID = getIndex(key).
  • If ID is not equal to -1, the key already exists in the cache,
    • Get the pair at index = ID, let it pair.
    • leftShift(ID + 1).
    • pair->value = value.
    • cache[size - 1] = pair
    • Return.
  • Create a new pair of (key, value), let it be pair.
  • If the size is less than the capacity,
    • Insert pair in cache at index = size, cache[size] = pair
    • Increment size by 1.
  • Otherwise,
    • Remove the first pair from the cache, by performing a left shift, leftShift(1).

Insert pair in cache at index = size - 1, cache[size - 1] = 

pair.

Time Complexity

O(Q*capacity), where ‘Q’ is the number of the given queries and ‘capacity’ is the maximum number of keys LRU Cache can store.

 

In the worst case, we will be iterating on the cache to left shift all pairs by one.

Space Complexity

O(capacity): where ‘capacity’ is the maximum number of keys LRU Cache can store.

 

In the worst case, we will only be maintaining the ‘capacity’ number of keys in storage.

Video Solution
Unlock at level 3
(75% EXP penalty)
Code Solution
(100% EXP penalty)
LRU Cache Implementation
All tags
Sort by
Search icon

Interview problems

Simple java solution using doubly linked list and hashmap

import java.util.HashMap;

 

public class LRUCache

{

    int size;

    Node least;

    Node recent;

    HashMap<Integer,Integer> hm;

    HashMap<Integer,Node> nodeMap;

    LRUCache(int capacity)

    {

        // Write your code here

        size = capacity;

        least = null;

        recent = null;

        hm =new HashMap<>();

        nodeMap = new HashMap<>();

    }

 

    public int get(int key)

    {

        // Write your code here

        if(hm.containsKey(key))

        {

            updateTheCache(key);

            return hm.get(key);

        }

        return -1;

    }

 

    public void put(int key, int value)

    {

        // Write your code here

        if(!hm.containsKey(key) && hm.size() >= size)

        {

            hm.remove(least.key);

            nodeMap.remove(least.key);

            hm.put(key, value);

            Node n = new Node(key);

            nodeMap.put(key, n);

            if(least == recent)// if cache capacity is 1

            {

                least = recent = n;

            }

            else

            {

                least = least.next;

                least.prev = null;

                recent.next = n;

                n.prev = recent;

                recent = n;

            }

 

        }

        else if(hm.containsKey(key))

        {

            updateTheCache(key);

            hm.put(key, value);

        }

        else

        {

            hm.put(key, value);

            Node n = new Node(key);

            nodeMap.put(key, n);

            if(least == null)

            {

               least = recent = n; 

            }

            else

            {

                recent.next = n;

                n.prev = recent;

                recent = n;

            }

        }

    }

    private void updateTheCache(int key)

    {

        if(least == recent)// the capacity of cache is 1 or in cache their is only one element as of now

        {return; }

        else

        {

            Node temp = nodeMap.get(key);

            if(least != temp && recent != temp)

            {

                temp.prev.next = temp.next;

                temp.next.prev = temp.prev;

                recent.next = temp;

                temp.prev = recent;

                recent = temp;

            }

            else if(least == temp) 

            {

                least=least.next;

                least.prev = null;

                recent.next = temp;

                temp.prev = recent;

                recent = temp;

            }

        }

    }

}

class Node

{

    Node prev;

    Node next;

    int key;

    public Node(int k)

    {

        key = k;

    }

}

 

 

19 views
0 replies
0 upvotes

Interview problems

Best Solution

#include<bits/stdc++.h>

class LRUCache

{

public:

    

    list<int> dll;

    map<int,pair<list<int>:: iterator,int>> mp;

 

    int n;

    LRUCache(int capacity)

    {

      n=capacity;

    }

 

    void RearrangeKey(int key)

    {

         dll.erase(mp[key].first);

 

         dll.push_front(key);

 

         mp[key].first=dll.begin();

    }

 

    int get(int key)

    {

       if(mp.find(key) == mp.end())

       {

           return -1;

       }

 

       RearrangeKey(key);

       

       return mp[key].second;

    }

 

    void put(int key, int value)

    {

         if(mp.find(key) == mp.end())

         {

            dll.push_front(key);

            mp[key]={dll.begin(),value};

            n--;

         } 

         else

         {

             mp[key].second=value;

             RearrangeKey(key);

         }

 

         if(n < 0)

         {

             int backValue=dll.back();

             mp.erase(backValue);

 

             dll.pop_back();

             n++;

         }

    }

};

175 views
0 replies
1 upvote

Interview problems

Using Linked hashmap in Java

public class LRUCache{

    LinkedHashMap<Integer, Integer> m;

    int capacity;

    LRUCache(int capacity){

        this.capacity = capacity;

        m = new LinkedHashMap<>();

    }

    public int get(int key){

        int ans = -1;

        if(m.containsKey(key)) {

            ans = m.get(key);

            m.remove(key);

            m.put(key, ans);

        }

        return ans;

    }

    public void put(int key, int value){

        m.remove(key);

        m.put(key, value);

        while(m.size() > capacity) {

            Set<Integer> s = m.keySet();

            int k = s.iterator().next();

            m.remove(k);

        }

    }

}

181 views
0 replies
1 upvote

Interview problems

Strivers soln || With explanation

#include<bits/stdc++.h>

 

class LRUCache

{

public:

 

    class node{

 

        public:

 

        int key, val;

        node* next;

        node* prev;

 

        node(int key, int val){

 

            this->key = key;

            this->val = val;

 

        }

 

    };

 

    node* head = new node(-1, -1);

    node* tail = new node(-1, -1);

 

    // Capacity of the window

    int cap;

 

    // Map to store the address of each node

    unordered_map<int, node*> m;

 

    LRUCache(int capacity)

    {

 

        cap = capacity;

        head->next = tail;

        tail->prev = head;

        

    }

 

    void addNode(node *newNode) {

        node *temp=head->next;

        newNode->next=temp;

        newNode->prev=head;

        head->next=newNode;

        temp->prev=newNode;

    }

    void deleteNode(node *delNode) {

        node *delPrev=delNode->prev;

        node *delNext=delNode->next;

        delPrev->next=delNext;

        delNext->prev=delPrev;

    }

 

    int get(int key)

    {

        

        // Check if the key already there in the window

        if(m.find(key) != m.end()){

 

            // Getting the node as its address is stored in map

            node* resNode = m[key];

 

            // Updating its position and move it to front as it now become most recently used

            m.erase(key);

            deleteNode(resNode);

            addNode(resNode);

 

            // Updating the address in map

            m[key] = head->next;

 

            // Returning its value

            return resNode->val;

 

        }

 

        // As the node is not present

        return -1;

 

    }

 

    void put(int key, int value)

    {

        

        // Case 1: Check if the node is already present delete it

        if(m.find(key) != m.end()){

 

            node* existingNode = m[key];

            m.erase(key);

            deleteNode(existingNode);

 

        }

 

        // Case 2: If the window is full

        if(m.size() == cap){

 

            // Delete the last element

            m.erase(tail->prev->key);

            deleteNode(tail->prev);

 

        }

 

        // Now add the node 

        addNode(new node(key, value));

        m[key] = head->next;

 

    }

    

};

422 views
1 reply
1 upvote

Interview problems

C++ || Easy Solution || LinkedList

#include<bits/stdc++.h>
class LRUCache {
public:
    class Node{
        public:
        int key, val;
        Node *next, *prev;
        Node(int KEY, int VAL) {key=KEY; val=VAL;}
    };
    int cap;
    unordered_map<int, Node*> mp;
    Node *head=new Node(-1, -1);
    Node *tail=new Node(-1, -1);
    LRUCache(int capacity) {
        cap=capacity;
        head->next=tail;
        tail->prev=head;
    }
    void addNode(Node *newNode) {
        Node *temp=head->next;
        newNode->next=temp;
        newNode->prev=head;
        head->next=newNode;
        temp->prev=newNode;
    }
    void deleteNode(Node *delNode) {
        Node *delPrev=delNode->prev;
        Node *delNext=delNode->next;
        delPrev->next=delNext;
        delNext->prev=delPrev;
    }

    int get(int key) {
        if(mp.find(key) != mp.end()) {
            Node *resNode=mp[key];
            int res=resNode->val;

            mp.erase(key);
            deleteNode(resNode);

            addNode(resNode);
            mp[resNode->key]=head->next;
            return res;
        }
        return -1;
    }

    void put(int key, int value) {
        if(mp.find(key) != mp.end()) {
            Node *existingNode=mp[key];
            mp.erase(key);
            deleteNode(existingNode);
        }
        if(mp.size() == cap) {
            mp.erase(tail->prev->key);
            deleteNode(tail->prev);
        }
        addNode(new Node(key, value));
        mp[key]=head->next;
    }
};
221 views
0 replies
0 upvotes

Interview problems

Easy Python Solution Using Dictionary

class LRUCache:
	# Initialize the LRU Cache
	def __init__(self, capacity):
		self.capacity = capacity
		self.cache = {}
	
	def get(self, key):
		if key not in self.cache:
			return -1
		value = self.cache.pop(key)
		self.cache[key] = value
		return value
	
	def put(self, key, value):
		if key in self.cache:
			self.cache.pop(key)
		else:
			if len(self.cache) == self.capacity:
				del self.cache[next(iter(self.cache))]
		self.cache[key] = value
79 views
0 replies
0 upvotes

Interview problems

Striver Approach || C++

#include<bits/stdc++.h>
using namespace std;

struct Node{
        int key,val;
        Node*next, *prev;
        Node(int key, int val){
            this->key = key;
            this->val = val;
            next=prev=nullptr;
        }
};

class LRUCache
{
public:
    int capacity;
    unordered_map<int,Node*> mp;
    Node *head, *tail;

    void deleteNode(Node* node){
        node->prev->next=node->next;
        node->next->prev=node->prev;
    }

    void insertNode(Node* node){
        node->next=head->next;
        head->next->prev=node;
        node->prev=head;
        head->next=node;
    }

    LRUCache(int capacity)
    {
        // Write your code here
        this->capacity = capacity;
        head = new Node(-1,-1);
        tail = new Node(-1,-1);
        head->next = tail;
        tail->prev = head;
    }

    int get(int key)
    {
        // Write your code here
        int ans=-1;
        if(!mp.count(key)){
            return ans;
        }
        ans = mp[key]->val;
        deleteNode(mp[key]);
        insertNode(mp[key]);
        return ans;
    }

    void put(int key, int value)
    {
        // Write your code here
        if(mp.count(key)){
            auto it=mp[key];
            deleteNode(it);
            it->val = value;
            insertNode(it);
        }
        else{
            if(mp.size()==capacity){
                mp[key] = new Node(key,value);
                mp.erase(tail->prev->key);
                deleteNode(tail->prev);
                insertNode(mp[key]);
            }
            else{
                mp[key] = new Node(key,value);
                insertNode(mp[key]);
            }
        }
    }
};
190 views
0 replies
0 upvotes

Interview problems

LRU Cache|| JAVA || Using Hash Map and Doubly Linked LIst

import java.util.HashMap;

public class LRUCache

{

    class Node{

        Node prev,next;

        int key,value;

        Node(int key,int value){

            this.key=key;

            this.value=value;

        }

    }

    Node head=new Node(0,0),tail=new Node(0,0);

    HashMap<Integer,Node> mpp=new HashMap<>();

    int size;

    LRUCache(int capacity)

    {

        size=capacity;

        head.next=tail;

        tail.prev=head;

    }

 

    public int get(int key)

    {

        if(mpp.containsKey(key)){

            Node node=mpp.get(key);

            remove(node);

            insert(node);

            return node.value;

        }

        return -1;

    }

 

    public void put(int key, int value)

    {

        if(mpp.containsKey(key))

        remove(mpp.get(key));

        if(mpp.size()==size)

        remove(tail.prev);

        insert(new Node(key, value));

    }

    public void remove(Node node){

        mpp.remove(node.key);

        node.prev.next=node.next;

        node.next.prev=node.prev;

    }

    public void insert(Node node){

        mpp.put(node.key,node);

        node.next=head.next;

        node.next.prev=node;

        head.next=node;

        node.prev=head;

    }

}

java

133 views
0 replies
1 upvote

Interview problems

Python Solution


from sys import stdin

class Node:
    def __init__(self,key,value):
        self.key, self.value = key,value
        self.next,self.prev=None,None

class LRUCache:
	# Initialize the LRU Cache
	def __init__(self, capacity):
		self.cap = capacity
		self.cache={}
		self.left,self.right = Node(0,0),Node(0,0)
		self.left.next,self.right.prev=self.right,self.left

	def remove(self,node):
		pre,nex=node.prev,node.next
		pre.next,nex.prev=nex,pre
	
	def insert(self,node):
		pre,nxt = self.right.prev,self.right
		pre.next=nxt.prev=node
		node.next,node.prev=nxt,pre
	
	def get(self, key):
		if key in self.cache:
			self.remove(self.cache[key])
			self.insert(self.cache[key])
			return self.cache[key].value
		return -1
	
	def put(self, key, value):
		if key in self.cache:
			self.remove(self.cache[key])
		self.cache[key]=Node(key,value)
		self.insert(self.cache[key])
		
		if len(self.cache) > self.cap:
			lru = self.left.next
			self.remove(lru)
			del self.cache[lru.key]   

# main
capacity, q = map(int, stdin.readline().rstrip().split(" "))

cache = LRUCache(capacity)

while q != 0:
	query = list(map(int, stdin.readline().rstrip().split()))

	if query[0] == 0:
		key = query[1]
		print(cache.get(key))
	elif query[0] == 1:
		key = query[1]
		value = query[2]
		cache.put(key, value)
	
	q -= 1

python

programming

49 views
0 replies
0 upvotes

Interview problems

lru cache problem

#include <unordered_map>

#include <list>

 

class LRUCache {

public:

    LRUCache(int capacity) : cap(capacity) {}

 

    int get(int key) {

        if (m.find(key) == m.end()) return -1;

        l.splice(l.begin(), l, m[key]);

        return m[key]->second;

    }

 

    void put(int key, int value) {

        if (m.find(key) != m.end()) {

            l.erase(m[key]);

            m.erase(key);

        }

        if (m.size() == cap) {

            int del = l.back().first;

            l.pop_back();

            m.erase(del);

        }

        l.push_front({key, value});

        m[key] = l.begin();

    }

 

private:

    int cap;

    std::list<std::pair<int, int>> l;

    std::unordered_map<int, std::list<std::pair<int, int>>::iterator> m;

};

153 views
0 replies
0 upvotes
Full screen
Console