题目描述
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。 实现 LRUCache 类:
- LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
- int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
- void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
解题思路
今天就来手撕这道经典的LRU算法,题目的要求是要保证get和put方法在O(1)的时间复杂度,自然想到用hashmap来保存数组,还需要定义一个双向链表,需要一个计算器来计算map中保存了多少个数,如果超过容量,就需要删除头节点。
AC 代码
class LRUCache {
//定义一个双向链表
public class Node{
private Node pre;
private Node next;
private int val;
private int key;
public Node(int key,int val){
this.key=key;
this.val=val;
}
}
private Node head,tail;
private int size;
private HashMap<Integer,Node> map;
private int count;
public LRUCache(int capacity) {
this.size=capacity;
this.map=new HashMap<>();
this.head=new Node(0,0);
this.tail=head;
this.count=0;
}
private void removeHead(){
map.remove(head.next.key);
head.next=head.next.next;
if(head.next!=null){
head.next.pre=head;
}
}
private void appendTotail(Node node){
tail.next=node;
node.pre=tail;
tail=node;
}
public int get(int key) {
if(!map.containsKey(key)){
return -1;
}
Node node=map.get(key);
if(node!=tail){
//删除该节点
Node pre=node.pre;
pre.next=node.next;
pre.next.pre=pre;
appendTotail(node);
}
return node.val;
}
public void put(int key, int value) {
Node cur=new Node(key,value);
//如果包含就不需要考虑了容量的大小
if(map.containsKey(key)){
Node node=map.get(key);
if(node!=tail){
//删除该节点
Node pre=node.pre;
pre.next=node.next;
pre.next.pre=pre;
}else{
tail=tail.pre;
}
}else{
if(count<size){
count++;
}else{
removeHead();
}
}
appendTotail(cur);
map.put(key,cur);
}
}
总结
首先定义双向链表要加上key值,这样删除头节点的时候,就可以直接删除map中的值,然后需要加强的是put方法