Thursday, June 22, 2017

LRU Cache



Following Solution to "LRU Cache" problem from Leetcode
Problem:
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(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.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.put(4, 4);    // evicts key 1
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4

Solution:
note: Please ignore the SOP's added for testing.

class DQueueNode {
    int key;
    int value;
    DQueueNode next;
    DQueueNode prev;
}

public class LRUCache {

    int cacheSize;
    int capacity;
    HashMap<Integer, DQueueNode> map = new HashMap<Integer, DQueueNode>();
    DQueueNode head = new DQueueNode();
    DQueueNode tail = new DQueueNode();
   
    private Integer pop(){
       
        Integer key = tail.prev.key;
        //System.out.println("Pop Tail : " + tail.prev.key);
        DQueueNode node = tail.prev;
        remove(node);
       
        //System.out.println("Pop : [head : " + head.next.key + ", tail : " + tail.prev.key + "]");
        return key;
    }
   
    private void add(DQueueNode node){
        DQueueNode nextNode = head.next;
        head.next = node;
       
        node.prev = head;
        node.next = nextNode;
        nextNode.prev = node;
       
            //System.out.println("Added : "+ node.key + ", Before [head : " + head.next.key + ", tail : " + tail.prev.key + "]");

    }
   
    private void remove(DQueueNode node){
       
        if(node.prev != null) node.prev.next = node.next;
        if(node.next != null) node.next.prev= node.prev;
       
          //System.out.println("Removed : "+ node.key + ", Before [head : " + head.next.key + ", tail : " + tail.prev.key + "]");
    }
   
    private void moveToHead(DQueueNode node) {
       // System.out.println("Move to Head : " + node.key);
       
              //  System.out.println("Before [head : " + head.next.key + ", tail : " + tail.prev.key + "]");

        remove(node);
        add(node);
               // System.out.println("Afrer [head : " + head.next.key + ", tail : " + tail.prev.key + "]");


    }
   
    public LRUCache(int capacity) {
        this.capacity = capacity;
       
        head.next = tail;
        tail.prev = head;
    }
   
    public int get(int key) {
       
        //System.out.println("Get key :" + key );
       
        if(map.get(key) != null){
            DQueueNode  node = map.get(key);
           
            moveToHead(node);
           
            // Put the end to the head
            return node.value;
        } else {
            return -1;
        }
    }
   
    public void put(int key, int value) {
       
        //System.out.println("Add key :" + key + ", value : " + value);
       
        if(map.get(key) != null){
           
            DQueueNode  node = map.get(key);
            node.value = value;
            map.put(key, node);
           
            moveToHead(node);
           
        } else {
           
            DQueueNode node = new DQueueNode();
            node.key = key;
            node.value = value;
           
            map.put(key, node);
           
            add(node);
            cacheSize++;
           
            //System.out.println("Map Size : " + map.size());
            if(cacheSize > capacity) {
                Integer tailNode = pop();
                //System.out.println("tail node popped : " + tailNode);
                map.remove(tailNode);
                cacheSize--;
                //System.out.println("Removed Item from Map. cacheSize : " + cacheSize);
                //System.out.println("tail : " + tail.prev.value);
            }
        }
       
        //System.out.println("End Put");
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

No comments:

Post a Comment