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.
import java.util.HashMap;
/*Key to solve:
* Data Structure of Least Recently Used Cache(LRU)
* Approach is to combine data structure of Map and DoubleLinkedList
* Analysis:
* Use HashMap to archive O(1) of get operation
* Use DoubleLinked list to archive O(1) of set operation that moving the specific node to the head
* and meanwhile remove the tail node
*/
public class LRUCache {
HashMap<Integer, DoublelistNode> map=new HashMap<Integer, DoublelistNode>();
int capacity;
DoublelistNode head;
DoublelistNode tail;
// initialize LRU
public LRUCache(int capacity) {
//initialize a HashMap object in capacity of base on user input
this.capacity = capacity;
head = new DoublelistNode(0, 0);
tail = new DoublelistNode(1, 1);
head.next = tail;
tail.prev = head;
}
public int get(int key) {
//if key exist, return value, and move the node to the head
if (map.containsKey(key)) {
DoublelistNode node = map.get(key);
move2Head(node);
return node.value;
} else {
return -1;
}
}
public void set(int key, int value) {
// if exist in the map, update the value, and move the node to the head
if (map.containsKey(key)) {
DoublelistNode node = map.get(key);
node.value = value;
move2Head(node);
}
// if not exist, and the cache not reach the capacity
else if (map.size() < capacity) {
DoublelistNode node = new DoublelistNode(key, value);
map.put(key, node);
move2Head(node);
// if not exist, and the cache reach the capacity
// remove the tail node is required
} else {
DoublelistNode node = new DoublelistNode(key, value);
map.put(key, node);
move2Head(node);
int tempK = removeEnd();
map.remove(tempK);
}
}
private void move2Head(DoublelistNode node) {
//if the node exist, disconnect current node
if(node.prev!=null && node.next!=null){
node.prev.next=node.next;
node.next.prev=node.prev;
}
//set node to the head
node.prev=head;
node.next=head.next;
head.next.prev=node;
head.next=node;
}
private int removeEnd() {
//store node of tail.prev to a temporary node
DoublelistNode temp = tail.prev;
//disconnect old tail node, update new tail node
tail.prev.prev.next=tail;
tail.prev=temp.prev;
//clear up connection of temp node
temp.prev=null;
temp.next=null;
return temp.key;
}
}
class DoublelistNode {
DoublelistNode prev;
DoublelistNode next;
int key;
int value;
DoublelistNode(int k, int v) {
this.key = k;
this.value = v;
}
}