Implement the LRUCache class:
LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
int get(int key) Return the value of the key if the key exists, otherwise return -1.
void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.
Follow up:
Could you do get and put in O(1) time complexity?
Example 1:
Input
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, null, -1, 3, 4]
Explanation
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // cache is {1=1}
lRUCache.put(2, 2); // cache is {1=1, 2=2}
lRUCache.get(1); // return 1
lRUCache.put(3, 3); // LRU key was 2, evicts key 2, cache is {1=1, 3=3}
lRUCache.get(2); // returns -1 (not found)
lRUCache.put(4, 4); // LRU key was 1, evicts key 1, cache is {4=4, 3=3}
lRUCache.get(1); // return -1 (not found)
lRUCache.get(3); // return 3
lRUCache.get(4); // return 4
设计一个LRU
即Least Recently Used,有get和put操作
思路:
设计一个list,把被访问过的数据提到list的head,这样慢慢的,没有访问的数据就会到tail。所以list是一个双向链表。
LRU在put的时候,如果已存数据量 > capacity,就需要删掉最近没有用过的那个,也就是tail位置的数据,把需要插入的数据插入到head。get的时候要把访问的数据移到head,表示最近刚访问过。
要在O(1)时间通过key找到value,所以需要一个HashMap。
在删掉tail位置的数据时,同时也要删掉在HashMap中对应的映射,那么要在O(1)时间通过tail部分删除的key找到HashMap中的key。所以list中要保存(key, value) pair,方便通过key找到HashMap需要删掉的key。
先利用java中的LinkedList实现
//116ms
class LRUCache {
private int capacity;
HashMap<Integer, Node> map = new HashMap<>();
Deque<Node> list = new LinkedList<>();
public LRUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
if(!map.containsKey(key)) return -1;
Node node = map.get(key);
list.remove(node);
list.offerFirst(node);
return node.getVal();
}
public void put(int key, int value) {
if(!map.containsKey(key)) {
Node node = new Node(key, value);
if(list.size() == capacity) {
Node tmp = list.pollLast();
map.remove(tmp.getKey());
}
map.put(key, node);
list.offerFirst(node);
} else {
Node node = map.get(key);
list.remove(node);
node.setVal(value);
list.offerFirst(node);
}
}
}
class Node{
private int key;
private int val;
public Node(int key, int val) {
this.key = key;
this.val = val;
}
public void setVal(int val) {
this.val = val;
}
public int getVal(){
return this.val;
}
public int getKey(){
return this.key;
}
}
用LinkedList实现运行时间116ms,查看discuss里较快的实现都是自己实现双向链表,于是自己实现一个简易版双向链表,它主要有几个功能,插入新数据时插入到head,remove一个元素,把元素从tail移到head
自己实现版的双向链表运行时间13ms
class LRUCache {
int capacity;
HashMap<Integer, Node> map = new HashMap<>();
Node head, tail;
int size;
public LRUCache(int capacity) {
this.capacity = capacity;
head = new Node(-1, -1);
tail = new Node(-1, -1);
head.next = tail;
tail.prev = head;
}
public int get(int key) {
if(!map.containsKey(key)) return -1;
Node node = map.get(key);
MoveToHead(node);
return node.val;
}
public void put(int key, int value) {
if(!map.containsKey(key)) {
Node node = new Node(key, value);
if(size == capacity) {
Node tmp = popTail();
map.remove(tmp.key);
}
addNodeToHead(node);
map.put(key, node);
} else {
Node node = map.get(key);
node.val = value;
MoveToHead(node);
}
}
void addNodeToHead(Node node) {
//在head后面加
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
size ++;
}
void removeNode(Node node) {
node.prev.next = node.next;
node.next.prev = node.prev;
size --;
}
void MoveToHead(Node node) {
removeNode(node);
addNodeToHead(node);
}
Node popTail() {
Node node = tail.prev; //要删除的node
removeNode(node);
return node;
}
}
class Node{
int key;
int val;
Node prev;
Node next;
public Node(int key, int val) {
this.key = key;
this.val = val;
}
}