题目:
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
题解
目标:淘汰最近不使用的内容
想要获得好的性能,需要满足两个条件:1.查找快.2.删除,插入快.
查找快可以使用hashMap,插入快使用链表.
- hashMap键值对设为<Integer,LRUnode> ,这样当查找到key,也就定位了LRUnode的位置,不用去遍历链表找结点.
- 伪头尾结点方便插入和删除结点
- 链表结点既有key,又有value,而不是只有value,是为了在删除最近不使用的结点时,拿到这个结点的key,然后顺利删除hashMap中保存的键值对(删除最近不使用的内容,不光要删除结点还少删除hashMap里的键值对,这样确保在查找时找不到已经删除的内容).
疑惑
下面三行代码
LRUnode del = tail.pre;
delnode(del);
map.remove(del.key);
开始我写的是
delnode(tail.pre);
map.remove(tail.pre.key);
造成删除结点错误,使得输出结果不对,但我不明白为什么会出错???
正确的代码:
class LRUCache {
class LRUnode{
int key;
int value;
public LRUnode pre;
public LRUnode next;
public LRUnode(){
};
public LRUnode(int _key, int _value){
key = _key;//基础差,写成了int key = _key,结果创建LRUnode失败,存进去的都是0.
value = _value;
}
}
int size;
int capacity;
HashMap<Integer,LRUnode> map = new HashMap<>();
public LRUnode head;
public LRUnode tail;
public LRUCache(int capacity) {//有参构造器
this.size = 0;
this.capacity = capacity;
head = new LRUnode();
tail = new LRUnode();
head.next = tail;
tail.pre = head;
}
public int get(int key) {
LRUnode tmp = map.get(key);
if(tmp==null){
return -1;
}
movefirst(tmp);
return tmp.value;
}
public void put(int key, int value) {
LRUnode tmp = map.get(key);
if(tmp != null){
tmp.value = value;
movefirst(tmp);
}else{
size++;
LRUnode newnode = new LRUnode(key, value);
putnode(newnode);
map.put(key,newnode);
if(size > capacity){
size--;
LRUnode del = tail.pre;
delnode(del);
map.remove(del.key);
}
}
}
public void delnode(LRUnode node){
node.pre.next = node.next;
node.next.pre = node.pre;
}
public void putnode(LRUnode node){
node.next = head.next;
head.next.pre = node;
head.next = node;
node.pre = head;
}
public void movefirst(LRUnode node){
delnode(node);
putnode(node);
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/