返回
LeetCode 146:LRU缓存机制之双剑合璧,巧破难题
前端
2023-12-25 02:27:06
导语:
大家好,欢迎来到LeetCode刷题打卡系列的第146期。今天我们要挑战的是一道经典的算法问题——LRU缓存机制。LRU(Least Recently Used)缓存是一种常见的缓存策略,它根据数据的最近使用情况来决定哪些数据应该被缓存,哪些数据应该被淘汰。
题目
设计一个LRU缓存机制,该缓存机制的大小为capacity。当缓存机制达到其容量时,它应该以最近最少使用的数据来替换新的数据。
解决方案:
为了解决这个问题,我们需要用到两种数据结构:哈希表和双链表。哈希表可以让我们在O(1)的时间复杂度内查找和插入数据,而双链表可以让我们在O(1)的时间复杂度内删除和插入数据。
思路:
- 使用哈希表来存储键值对。哈希表的键是数据本身,哈希表的值是数据在双链表中的节点。
- 使用双链表来记录数据的最近使用情况。双链表的头部是最近使用的元素,双链表的尾部是最久未使用的数据。
- 当需要将一个新的数据插入到缓存中时,首先检查哈希表中是否存在该数据。如果存在,则将该数据移动到双链表的头部。如果不存在,则将该数据插入到双链表的头部,并将双链表的尾部的数据删除。
- 当缓存达到其容量时,则将双链表尾部的数据删除。
代码实现:
class LRUCache {
private int capacity;
private HashMap<Integer, Node> map;
private Node head;
private Node tail;
public LRUCache(int capacity) {
this.capacity = capacity;
this.map = new HashMap<>();
this.head = new Node(null, null);
this.tail = new Node(null, null);
head.next = tail;
tail.prev = head;
}
public int get(int key) {
if (!map.containsKey(key)) {
return -1;
}
Node node = map.get(key);
moveToHead(node);
return node.value;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
Node node = map.get(key);
node.value = value;
moveToHead(node);
} else {
Node node = new Node(key, value);
addToHead(node);
map.put(key, node);
if (map.size() > capacity) {
Node tailNode = tail.prev;
removeNode(tailNode);
map.remove(tailNode.key);
}
}
}
private void moveToHead(Node node) {
removeNode(node);
addToHead(node);
}
private void addToHead(Node node) {
node.next = head.next;
head.next.prev = node;
head.next = node;
node.prev = head;
}
private void removeNode(Node node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
private class Node {
int key;
int value;
Node prev;
Node next;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
}
结语:
LRU缓存机制是一个非常经典的算法问题,也是面试中经常遇到的问题。通过这篇文章,我们学习了如何使用哈希表和双链表来实现LRU缓存机制。我希望这篇文章对大家有所帮助,也希望大家能够在LeetCode刷题打卡系列中有所收获。
参考文献: