Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述
-
设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。
-
它应该支持以下操作: 获取数据 和 写入数据 。
-
获取数据 – 如果密钥 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
-
写入数据 – 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
-
示例
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
复制代码
思路分析
- 这道题的题目描述容易让人产生误解,更常用的语言表达应该是当缓存将要超出最大容量时,删除最久没有使用的 。
- 当链表或者数组储存对应的 时,要遵从一头用于插入 ,另一头用于删除 。类似于先进先出数据结构。因为设计频繁的出入和删除,我们要选链表而不选数组。
- 对于
put
, 当插入的 不存在链表中时,直接在链表尾部插入,若链表此时容量大于最大限制容量,则删除链表头部一个结点即可;当插入的 已经存在链表中时,先删除链表中对应 的结点,再在尾部插入结点。 - 对于
get
, 若 不存在链表中直接返回 -1 ,不用对链表进行处理;若 存在链表中,先将链表中对应 的结点删除,然后将其加入链表尾部。 - 对于删除链表中的结点,可以用哈希表记录 对应的结点,然后进行删除处理。
AC 代码
class LRUCache {
class Node {
private int key;
private int value;
private Node next;
private Node pre;
public Node() {}
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
Map<Integer,Node> map = new HashMap<>();
Node head;
Node tail;
int capacity;
public LRUCache(int capacity) {
this.capacity = capacity;
head = new Node();
tail = new Node();
head.next = tail;
tail.pre = head;
}
private void add(int key, int value) {
Node node = new Node(key, value);
tail.pre.next = node;
node.pre = tail.pre;
node.next = tail;
tail.pre = node;
map.put(key,node);
}
private void remove() {
Node t = head.next;
head.next = head.next.next;
head.next.pre = head;
t.next = null;
t.pre = null;
map.remove(t.key);
}
private int remove(int key) {
Node node = map.get(key);
Node p = node.pre;
Node n = node.next;
p.next = n;
n.pre = p;
node.next = null;
node.pre = null;
return node.value;
}
public int get(int key) {
if (!map.containsKey(key)) return -1;
int value = remove(key);
add(key,value);
return value;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
remove(key);
add(key, value);
} else {
if (map.size() == capacity) {
remove();
}
add(key, value);
}
}
}
复制代码
总结
- 本题非常适合拿双向链表来练手,动动小手多多益善!
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END