题目连接.
运用所掌握的数据结构,设计和实现一个==LRU(最近最少使用)==缓存机制,支持一下操作:
1.获取数据get:如果key在缓存中,则获取秘钥的值,否则返回-1;
2.写入数据put:如果秘钥不存在,则写入数据值,当到达上限时,应该删除最近最少使用的值,为新的数据流出空间。
3.LRU的容量为2.
LRU缓存机制
LRU(The Least Recently Used,最近最久未使用算法)是一种常见的缓存算法,在很多分布式缓存系统(Redis,Memcached) 中都有广泛引用。
算法思想:
如果一个数据在最近一段时间没有被访问到,那么可以认为在未来被访问到的可能性也很小,因此,当空间满的时候,最久没有访问的数据最先被置换。
实现:最朴素的思想就是数组+时间戳的方式,不过效率低下,我们可以使用双向链表+哈希表实现。
解法
解题思路
知识点:哈希表、双向链表,LRU缓存机制。
1.初始化双向链表时设置虚拟头结点和虚拟为结点:
- put(1, 1):由于链表容量为0,直接放入即可:
- put(2, 2)
此时链表容量为1,可以新增节点,且无需删除节点
- get(1)
此时我们将(1, 1)节点从链表尾部删除,并将其新增至链表头部:
- put(3, 3):此时容量是2,如果新增节点,那么就先删除节点,因此先删除(2, 2),再新增(3,3)节点:
整个操作过程,由于使用了hash表来定位节点位置,put和get的操作时间复杂度为O(1),空间复杂度为O(n)
class LRUCache{
//定义节点
private class Node{
private int key;
private int value;
private Node pre;
private Node next;
public Node() {}
public Node(int key, int value){
this.key = key;
this.value = value;
}
}
//虚拟头结点和虚拟尾节点
private Node dummyHead = new Node();
private Node dummyTail = new Node();
//LRUCache的容量和当前节点的数量
private int capacity;
private int size;
//HashMap用来查询,存入双向链表的同时,放一份在HashMap
private HashMap<Integer, Node> hashMap = new HashMap<>();
//添加至头结点
private void add(Node node){
Node originHead = dummyHead.next;
//即在originHead 和 dummyHead中间插入node
//双向链表
dummyHead.next = node;
node.pre = dummyHead;
node.next = originHead;
originHead.pre = node;
}
//删除某节点
private void del(Node node){
Node preNode = node.pre;
Node nextNode = node.next;
preNode.next = nextNode;
nextNode.pre = preNode;
node.pre = null;
node.next = null;
}
//初始化一个LRU
public LRUCache(int capacity){
dummyHead.next = dummyTail;
dummyTail.pre = dummyHead;
this.capacity = capacity;
size = 0;
}
public int get(int key){
//通过hashmap可以get到元素
Node node = hashMap.get(key);
//如果链表中没有,则返回-1
if(null == node) return -1;
//在原地删除这个节点,并将整个节点移动到头部
del(node);
add(node);
return node.value;
}
public void put(int key, int value){
Node node = hashMap.get(key);
//如果链表中存在该节点,则更新该节点并放到头结点
if(null != node){
//更新节点的值
node.value = value;
del(node);
add(node);
}else{
//如果链表中不存在该元素
//1.如果此时链表还没装满
if (size <= capacity) {
size++;
}else{
Node delNode = dummyTail.pre;
hashMap.remove(delNode.key);
del(delNode);
}
Node newNode = new Node(key, value);
add(newNode);
hashMap.put(key,newNode);
}
}
}