Problem:
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.
Thought:
Use a HashMap along with a doubly linked list to achieve the O(1) running time for both get and set.
package leetcode_Java;
import java.util.Comparator;
import java.util.HashMap;
import java.util.PriorityQueue;
public class LRUCache {
HashMap <Integer, ListEntry> map = new HashMap<Integer, ListEntry>();
DoublyLinkedList list;
public LRUCache(int capacity) {
list = new DoublyLinkedList(capacity, map);
}
public int get(int key) {
ListEntry entry = map.get(key);
if(entry == null){
return -1;
}else{
list.MoveToHead(entry);
return entry.value;
}
}
public void set(int key, int value) {
ListEntry entry = map.get(key);
if(entry == null){
ListEntry newEntry = new ListEntry(null, null, value, key);
map.put(key, newEntry);
list.Add(newEntry);
}else{
entry.value = value;
list.MoveToHead(entry);
}
}
}
class DoublyLinkedList{
ListEntry head;
ListEntry tail;
int capacity;
int currentSize;
HashMap <Integer, ListEntry> map;
public DoublyLinkedList(int capacity, HashMap <Integer, ListEntry> map){
this.capacity = capacity;
this.currentSize = 0;
this.map = map;
}
public void Add(ListEntry entry){
if(currentSize < capacity){
if(head == null){
head = entry;
tail = entry;
}else{
head.prev = entry;
entry.next = head;
head = entry;
}
currentSize++;
}else{
head.prev = entry;
entry.next = head;
head = entry;
//remove tail
map.remove(tail.key);
tail = tail.prev;
tail.next = null;
}
}
//Assume that entry has already existed somewhere in the doubly linked list
public void MoveToHead(ListEntry entry){
if(entry == head){
return;
}else if(entry == tail){
tail = entry.prev;
entry.prev.next = null;
}else{ // in the middle
entry.prev.next = entry.next;
entry.next.prev = entry.prev;
}
head.prev = entry;
entry.next = head;
entry.prev = null;
head = entry;
}
}
// Node type of a doubly linked list
class ListEntry{
ListEntry prev;
ListEntry next;
int value;
int key;
public ListEntry(ListEntry prev, ListEntry next, int value, int key) {
super();
this.prev = prev;
this.next = next;
this.value = value;
this.key = key;
}
}