原题如下:
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.
思路:用一个数据结构来实现LRU,对LRU的解释为:Replace the page that has not been used for the longest period of time,即最长时间未被访问的页面,访问包括set和get。
很容易想到用TreeMap来实现,但是实现过程还是有点曲折,TreeMap是有序的Map,是根据key排序的,TreeMap和HashMap根据hashCode()方法和equals()方法来比较key值是否相等,但TreeMap是根据key元素的compareTo方法来排序,在这里因为我们关心的是时间,所以我们希望元素安装时间排序,同时TreeMap结构的key中包含题目中的key值,所以需要一种新的数据结构KeyTime,KeyTime包括key和访问时间,让TreeMap安装访问时间排序,所以需要重写compareTo方法。
完整代码如下:
keyTime用于保存key和访问时间。caches用来保存KeyTime和对应的值。注意每次访问都要修改时间。
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
//Replace the page that has not been used for the longest period of time
public class LRUCache {
private int size;
long timeCounter = 0; //模拟时间点
private HashMap<Integer,Long> keyTime = new HashMap<Integer,Long>(); //不需要有序,这个地方改成TreeMap会变慢(要维持顺序)
private TreeMap<KeyTime,Integer> caches = new TreeMap<KeyTime,Integer>(); //有序
public LRUCache(int capacity) {
this.size = capacity;
}
public int get(int key) {
if(keyTime.containsKey(key)){
long newTime = timeCounter++;
KeyTime kt = new KeyTime(key,keyTime.get(key).longValue());
int value = caches.get(kt);
keyTime.put(key, newTime);
caches.remove(kt);
caches.put(new KeyTime(key,newTime), value);
return value;
}
return -1;
}
public void set(int key, int value) {
long newTime = timeCounter++;
if(keyTime.containsKey(key)){ //已经存在
long oldTime = keyTime.get(key);
keyTime.put(key, newTime);
caches.remove(new KeyTime(key,oldTime));
caches.put(new KeyTime(key,newTime), value);
}else if(keyTime.size()<this.size){ //不存在但未满
keyTime.put(key, newTime);
caches.put(new KeyTime(key,newTime), value);
}else{ //不存在,而且满了
Map.Entry<KeyTime,Integer> firstEntry = caches.firstEntry();
int k = firstEntry.getKey().key;
long time = firstEntry.getKey().time;
caches.remove(new KeyTime(k,time));
keyTime.remove(k);
keyTime.put(key, newTime);
caches.put(new KeyTime(key,newTime), value);
}
}
class KeyTime implements Comparable<KeyTime>{
int key;
long time;
public KeyTime(int key,long time){
this.key = key;
this.time = time;
}
@Override
public int compareTo(KeyTime o) { //重写compareTo方法
if(this.time<o.time){
return -1;
}else if(this.time>o.time){
return 1;
}
return 0;
}
}
}