文章总结的思路参考(图我也是白嫖的)
https://www.bilibili.com/video/BV1hp4y1x7MH
- 要求在O(1)的时间复杂度完成get操作,我们想到的数据结构是Map。但是,put操作是需要记录下来哪个是(最近最少使用)需要被删除更新的键,Map做不到。
- 插入和删除的操作时间复杂度都是O(1)的,我们自然想到的数据结构就是链表。但是问题就出现在查找的操作了,链表的查找时间复杂度是O(n)。
- 总结一下就是查找用Map,插入用双向链表。
AC代码
public class LRUCache {
HashMap<Integer,Node> map;
DoubleLinkledLst cache;
int capacity;
public LRUCache(int capacity){
map=new HashMap<Integer, Node>();
cache=new DoubleLinkledLst();
this.capacity=capacity;
}
public void put(int key,int val){
Node newNode=new Node(key, val);
if(map.containsKey(key)){
cache.delete(map.get(key));
cache.addFirst(newNode);
map.put(key,newNode);
}else {//如果map里没有该key
if(map.size()==capacity) {//满了就删
int k = cache.deleteLast();//删除链表队尾的最近最少使用的元素
map.remove(k);
}
cache.addFirst(newNode);//加到双向链表头部作为最近使用的缓存
map.put(key,newNode);
}
}
public int get(int key){
if(!map.containsKey(key)) return -1;
int val=map.get(key).val;
put(key,val);//查看过需要再放到头节点
return val;
}
}
//head是最近使用,tail是最近最少使用
class DoubleLinkledLst{
Node head;//头节点
Node tail;//尾节点
public DoubleLinkledLst(){
head=new Node(0,0);
tail=new Node(0,0);
//建立连接
head.next=tail;
tail.pre=head;
}
//加在头节点的后一个位置上
public void addFirst(Node newNode){
newNode.next=head.next;//新节点的next指针指向head节点的下一个节点
newNode.pre=head;//新节点的pre指针指向head节点
head.next.pre=newNode;//使原本头节点的下一个节点的pre指针指向先节点
head.next=newNode;//head节点的next指向新节点
}
//删除双向链表的某一个节点
public int delete(Node n){
int key=n.key;
n.next.pre=n.pre;
n.pre.next=n.next;
return key;
}
//删除最后一个节点
public int deleteLast(){
if(head.next==tail) return -1;
return delete(tail.pre);
}
}
class Node{
int key;
int val;
Node pre;
Node next;
public Node(int key,int val){
this.key=key;
this.val=val;
}
}