题目描述
请你设计并实现一个满足 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) 的平均时间复杂度运行。
测试用例
示例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
解法
解法:双链表+HashMap
HashMap:
Key | Value |
---|---|
1 | node1 |
2 | node2 |
双链表:文章来源:https://www.toymoban.com/news/detail-564563.html
(head)[ | ] -><- (node1)[ 1 | value1 ] -><- (node2)[ 2 | value2 ] -><- (tail)[ | ]文章来源地址https://www.toymoban.com/news/detail-564563.html
class LRUCache {
/**
定义双向链表类
*/
class DoubleLinkedNode {
int key, value;
DoubleLinkedNode prev, next;
DoubleLinkedNode () {
}
DoubleLinkedNode (int _key, int _value) {
key = _key;
value = _value;
}
}
/**
size为存放数据长度, capacity为最大缓存容量
*/
private int size, capacity;
/**
双向链表头节点和尾节点
*/
private DoubleLinkedNode head, tail;
private Map<Integer, DoubleLinkedNode> map = new HashMap<>();
public LRUCache(int capacity) {
this.capacity = capacity;
this.size = 0;
head = new DoubleLinkedNode();
tail = new DoubleLinkedNode();
head.next = tail;
tail.next = head;
}
public int get(int key){
if (size <= 0) {
return -1;
}
DoubleLinkedNode node = map.get(key);
if (node == null) {
// LRU中不存在元素
return -1;
} else {
// LRU中存在元素
// 将元素移到head处,表示已访问过
moveToHead(node);
return node.value;
}
}
public void put(int key, int value) {
// 判断是否已经存在该节点
DoubleLinkedNode node = map.get(key);
if (node == null) {
// 节点为空,直接放入
// 生成节点
DoubleLinkedNode newNode = new DoubleLinkedNode(key, value);
// 存放到头部, 最近访问
addToHead(newNode);
// map加上该节点
map.put(key, newNode);
size++;
// 判断数据长度是否大于最大的LRU容量
if (size > capacity) {
// 移除出LRU
DoubleLinkedNode tailRemoved = removeTail();
// map相应移出该元素
map.remove(tailRemoved.key);
size--;
}
} else {
// 变更数据值value
node.value = value;
// 移动到头部,最近访问
moveToHead(node);
}
}
private void addToHead (DoubleLinkedNode node) {
node.next = head.next;
head.next.prev = node;
head.next = node;
node.prev = head;
}
/**
移动节点到head处
*/
private void moveToHead (DoubleLinkedNode node) {
// 先移出
// 前一个元素指向后一个元素
node.prev.next = node.next;
// 后一个元素指向前一个元素
node.next.prev = node.prev;
// 再放入
node.next = head.next;
head.next.prev = node;
head.next = node;
node.prev = head;
}
private DoubleLinkedNode removeTail () {
DoubleLinkedNode p = tail.prev;
tail.prev.prev.next = tail;
tail.prev = p.prev;
return p;
}
}
到了这里,关于Leetcode 146. LRU 缓存(Hashmap+双链表)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!