大家好!我是曾续缘💕
今天是《LeetCode 热题 100》系列
发车第 35 天
链表第 14 题
❤️点赞 👍 收藏 ⭐再看,养成习惯
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。实现LRUCache
类:
LRUCache(int capacity)
以 正整数 作为容量capacity
初始化 LRU 缓存int get(int key)
如果关键字key
存在于缓存中,则返回关键字的值,否则返回-1
。void put(int key, int value)
如果关键字key
已经存在,则变更其数据值value
;如果不存在,则向缓存中插入该组key-value
。如果插入操作导致关键字数量超过capacity
,则应该 逐出 最久未使用的关键字。函数
get
和put
必须以O(1)
的平均时间复杂度运行。示例:
输入 ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] 输出 [null, null, null, 1, null, -1, null, -1, 3, 4] 解释 LRUCache lRUCache = new LRUCache(2); lRUCache.put(1, 1); // 缓存是 {1=1} lRUCache.put(2, 2); // 缓存是 {1=1, 2=2} lRUCache.get(1); // 返回 1 lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3} lRUCache.get(2); // 返回 -1 (未找到) lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3} lRUCache.get(1); // 返回 -1 (未找到) lRUCache.get(3); // 返回 3 lRUCache.get(4); // 返回 4提示:
难度:💖💖
1 <= capacity <= 3000
0 <= key <= 10000
0 <= value <= 105
- 最多调用
2 * 105
次get
和put
解题方法
这道题目需要设计并实现一个满足LRU(最近最少使用)缓存约束的数据结构。为了实现LRU缓存,我们可以采用哈希表和双向链表的组合来解决问题。
我们使用哈希表来快速查找关键字所对应的缓存节点,哈希表的键是关键字,值是节点指针。这样可以以O(1)的时间复杂度快速找到某个关键字对应的节点。
为了维护缓存的最近访问顺序,我们使用双向链表。双向链表中的节点按照访问顺序从头到尾依次排列,头部是最近访问过的节点,尾部是最久未被访问的节点。这样,当节点被访问时,我们可以快速将它移到链表的头部,而当需要淘汰节点时,可以直接删除尾部节点。
我们使用head和tail节点来简化边界条件的处理,它们不存储任何数据,只作为辅助节点。插入新节点时,我们将新节点插入到head节点之后,删除节点时,我们删除tail节点之前的节点。
Code
查看代码
java
class LRUCache {
class Node{
int key;
int value;
Node prev;
Node next;
public Node(){key = -1;};
public Node(int k, int v){
key = k;
value = v;
}
}
private Map<Integer, Node> mp = new HashMap<Integer, Node>();
private int capacity;
private Node head, tail;
public LRUCache(int capacity) {
this.capacity = capacity;
head = new Node();
tail = new Node();
head.next = tail;
tail.prev = head;
}
public int get(int key) {
if(mp.containsKey(key)){
Node node = mp.get(key);
node.prev.next = node.next;
node.next.prev = node.prev;
moveToHead(node);
return node.value;
}else{
return -1;
}
}
public void put(int key, int value) {
if(mp.containsKey(key)){
Node node = mp.get(key);
node.value = value;
node.prev.next = node.next;
node.next.prev = node.prev;
moveToHead(node);
}else{
Node node = new Node(key, value);
mp.put(key, node);
if(mp.size() > capacity){
Node delNode = tail.prev;
mp.remove(delNode.key);
tail.prev.prev.next = tail;
tail.prev = tail.prev.prev;
}
moveToHead(node);
}
}
private void moveToHead(Node node){
head.next.prev = node;
node.next = head.next;
node.prev = head;
head.next = 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);
*/