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.
11/3
这道题本来做的时候也没有搞得很明白, 到狗的onsite的时候写code的时候就不行了
当时问的时候我立马就说出了可以用linked list + hashmap来做, 然后面试官的followup就是如果要求O(1)的时间应该怎么操作, 我当时也答出来了, 用doubly linked list+hashmap, 但是写code的时候写得问题多多, 只查出来一些null pointer exception, 最囧的是对于map的操作只做了删除而没有做插入, 这一关做的不好
现在重访这道题, leetcode也做了一些变化, 原来的code没法通过现在的test case了, 应该是时间上有了更高的要求。 这道题相比于regex expression match的两个难题, 考得更多的应该是你写的时候能不能做到bug-free, 而本身的算法难度则不是很大
这道题的code要好几十行
public class LRUCache {
public class Node{
public int key;
public int val;
public Node prev;
public Node next;
public Node(int k, int v){
key = k;
val = v;
prev = null;
next = null;
}
}
private int capacity = 0;
private Node head = null;
private Node tail = null;
private Map<Integer,Node> map = null;
public LRUCache(int capacity) {
this.capacity = capacity;
head = null;
tail = null;
map = new HashMap<Integer, Node>();
}
public int get(int key) {
Node found = map.get(key);
if(found == null){
return -1;
}else{
// need to reorder
set(key, found.val);
return found.val;
}
}
// the following three methods are just manipulation on the doubly linked list
public void addNode(Node node){
if(head == null){ // both the head and tail are null
head = node;
tail = node;
}else{
node.next = head;
head.prev = node;
head = node;
}
}
public void evictTail(){
if(tail == null) return; // this is a bad case!
if(head == tail){ // just one node in the linked list
head = null;
tail = null;
}else{
tail = tail.prev;
tail.next = null;
}
}
public void reorder(Node node, Node found){
// add the node and then remove found
addNode(node);
// note that now found cannot be the head; if it is the tail, there is at least a node before it.
if(found == tail){
tail = tail.prev;
tail.next = null;
}else{
Node prev = found.prev; // cannot be null
Node next = found.next;
prev.next = next;
if(next != null) next.prev = prev;
}
}
public void set(int key, int value) {
Node found = map.get(key);
if(found == null){ // add the node to the linked list, may need to evict
int num = map.keySet().size();
if(num < capacity){ // no need to evict, simply add
Node node = new Node(key,value);
map.put(key,node);
addNode(node);
}else{ // evict the tail
map.remove(tail.key);
evictTail();
Node node = new Node(key,value);
map.put(key,node);
addNode(node);
}
}else{ // just reorder
// found is not null
Node node = new Node(key,value);
reorder(node, found);
map.put(key,node);
}
}
}