题目
146. LRU 缓存【中等】
题解
关键问题是如何查找最久未使用的关键字,想过构建新的类(key,value,time)
,用优先队列存,但是需要排序,时间复杂度大于O(1),其余方法似乎都需要排序,不可能用O(1)的时间复杂度完成
官方给出的解法是用哈希表+双向链表,原因如下:
因此采用双向链表的思路是:
- 最近访问的结点放第一个【头插】
- 最久未使用的结点放末尾,capacity不够,则删除最后一个结点【尾删】
- 访问已有结点,则将它挪到第一个位置【删除+头插】
//结点
class Node{
public int key;
public int value;
public Node prev,next;
public Node(){
prev=null;
next=null;
}
public Node(int k,int v){
key=k;
value=v;
prev=null;
next=null;
}
}
//双向链表
class DoubleList{
private Node head;//虚拟头结点
private Node tail;//虚拟尾结点
//构造方法
public DoubleList(){
head=new Node();
tail=new Node();
head.next=tail;
tail.prev=head;
}
//头插
public void insert(Node p){
p.next=head.next;
p.prev=head;
head.next=p;
p.next.prev=p;
}
//尾删
public Node remove(){
Node p=tail.prev;
p.prev.next=tail;
tail.prev=p.prev;
return p;
}
//删除任意结点p
public void remove(Node p){
p.prev.next=p.next;
p.next.prev=p.prev;
}
}
class LRUCache {
private int capacity;
private Map<Integer,Node>hashMap;//哈希表
private DoubleList doubleList;//双向链表
public LRUCache(int capacity) {
this.capacity=capacity;
hashMap=new HashMap<Integer,Node>();
doubleList=new DoubleList();
}
public int get(int key) {
if(hashMap.containsKey(key)){
Node p=hashMap.get(key);
doubleList.remove(p);//删除原位置
doubleList.insert(p);//头插
return p.value;
}
return -1;
}
public void put(int key, int value) {
//key已经存在
if(get(key)!=-1){//get(key)中已经包含了把key结点挪到第一个的操作
hashMap.get(key).value=value;
}
//key不存在
else{
Node p=new Node(key,value);
//超过capacity
if(hashMap.size()>=capacity){
Node tmp=doubleList.remove();//尾删
hashMap.remove(tmp.key);//哈希表中删除
}
doubleList.insert(p);//头插
hashMap.put(key,p);
}
}
}
主要考察双向链表的应用和实现,需要熟记