掘金团队号上线,助你 Offer 临门! 点击 查看详情
一、题目描述:
运用你掌握的数据结构,实现一个LRU(最近最少使用)缓存机制.
LRU缓存的实现:
- LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
- int get(int key) 如果key对应的value在缓存中则返回value,否则返回-1;
- void put(int key,int value) 如果key对应的value已经存在,则替换该value,如果不存在,则插入该键值对到缓存中,如果缓存达到了存储上限,则删除最久未使用的元素,为新元素的存储腾开空间
- 要求get和put方法的时间复杂度控制在O(1)
二、思路分析: LRU缓存常规思路就是使用链表的方式实现,但是常规链表实现的缓存的查询复杂度为O(n),需要遍历链表,所以我们需要一个Hash映射表做一个<键-链表节点的映射>,这样查询的复杂度就是O(1)了。对应Java中实现的类就是LinkedHashMap,查看源码即可
三、AC代码:
class LRUCache {
//Java中的LinkedHashMap = 双向链表+hashMap,实现O(1)复杂度
//双向链表+HashMap
class DLinkNode {
DLinkNode prev ;
DLinkNode next;
int key;
int value;
public DLinkNode(){}
public DLinkNode(int key,int value){this.key = key;this.value = value;}
}
//hash表
Map<Integer,DLinkNode> map ;
//一个空头,一个空尾节点
DLinkNode head;
DLinkNode tail;
//容量
private int capacity ;
//实时数量
private int size;
public LRUCache(int capacity) {
this.size = 0;
this.capacity = capacity;
this.head = new DLinkNode();
this.tail = new DLinkNode();
map = new HashMap(capacity);
this.head.next = tail;
this.tail.prev = head;
}
public int get(int key) {
DLinkNode valueNode = map.get(key);
if(valueNode == null){
return -1;
}
removeNode(valueNode);
addHead(valueNode);
return valueNode.value;
}
public void put(int key, int value) {
DLinkNode valueNode = map.get(key);
//不存在该值时
if(valueNode == null){
if(this.size >= this.capacity){
//从链表中删除
DLinkNode removedNode = removeOldest();
//从HashMap中删除
map.remove(removedNode.key);
--size;
}
DLinkNode temp = new DLinkNode(key,value);
addHead(temp);
map.put(key,temp);
++size;
}else{
//存在该值时,更新HashMap中的值
valueNode.value = value;
//移动该节点到头部
removeNode(valueNode);
addHead(valueNode);
}
}
//删除链表中的某一个节点O(1)
private void removeNode(DLinkNode valueNode){
valueNode.prev.next = valueNode.next;
valueNode.next.prev = valueNode.prev;
}
//删除最老的元素
private DLinkNode removeOldest(){
DLinkNode oldest = this.tail.prev;
removeNode(oldest);
return oldest;
}
//将一个节点添加到链表的头部O(1)
private void addHead(DLinkNode valueNode){
this.head.next.prev = valueNode;
valueNode.next = this.head.next;
valueNode.prev = this.head;
this.head.next = valueNode;
}
}
四、总结