这是一个很经典的面试题
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache
类:
LRUCache(int capacity)
以 正整数 作为容量capacity
初始化 LRU 缓存int get(int key)
如果关键字key
存在于缓存中,则返回关键字的值,否则返回-1
。void put(int key, int value)
如果关键字key
已经存在,则变更其数据值value
;如果不存在,则向缓存中插入该组key-value
。如果插入操作导致关键字数量超过capacity
,则应该 逐出 最久未使用的关键字。
函数 get
和 put
必须以 O(1)
的平均时间复杂度运行。
这是一个设计数据结构的题
如果没有第三个要求,HashMap+List就可以是实现,
可是还需要O(1)的复杂度
可以使用双向链表加Hash表去解决,为什么要用hash表了,因为要快速判断这个key存在于这个链表,
解法一:自定义双向链表
class LRUCache3{
private static class Node{
int key,value;
Node pre,next;
public Node(int key,int value){
this.key=key;
this.value=value;
}
}
private int capacity;
private Node head=new Node(0,0);
private HashMap<Integer,Node> map=new HashMap<>();
public LRUCache3(int capacity) {
this.capacity=capacity;
head.pre=head;
head.next=head;
}
public int get(int key){
if(!map.containsKey(key)){
return -1;
}
Node k=map.get(key);
remove(k);
add(k);
return k.value;
}
public void put(int key,int value){
if(map.containsKey(key)){
Node node = map.get(key);
node.value=value;
remove(node);
add(node);
return ;
}
if(map.size()==capacity){
Node last = head.pre;
remove(last);
map.remove(last.key);
}
add(new Node(key,value));
}
private void remove(Node k){
k.pre.next=k.next;
k.next.pre=k.pre;
}
private void add(Node k){
k.pre=head;
k.next=head.next;
k.pre.next=k;
k.next.pre=k;
}
}
解法二:使用LinkedHashmap 本身自带双向链表
LinkedHashMap
LinkedHashMap<Integer,String> linkedHashMap = new LinkedHashMap<>(16,0.75f,true);
boolean accessOrder决定按什么排序,为true则为按访问顺序,为false则为插入顺序
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
如果按照插入顺序写会固定不变,所以应该用true
class LRUCache2{
// LinkedHashMap 最早是在上面, 最近使用的在下面。
private int capacity;
private LinkedHashMap<Integer, Integer> map;
public LRUCache2(int capacity) {
this.capacity = capacity;
map = new LinkedHashMap<>();
}
public int get(int key) {
Integer remove = map.remove(key);
if(remove !=null ){
map.put(key,remove);
return remove;
}
return -1;
}
public void put(int key, int value) {
if(map.remove(key)!=null){
map.put(key,value);
return ;
}
if(map.size()==capacity){
map.remove(map.keySet().iterator().next());
}
map.put(key,value);
}
}
第三种 继承LinkedHashMap
class LRUCache extends LinkedHashMap<Integer, Integer>{
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
private final int capacity;
public LRUCache(int capacity) {
super(capacity, DEFAULT_LOAD_FACTOR, true);
this.capacity = capacity;
}
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return size() > capacity;
}
public int get(int key) {
return super.getOrDefault(key, -1);
}
}