返回
NC93 设计 LRU 缓存结构:理解 Map 应用,巧妙解题
前端
2023-10-17 11:37:30
导言
最近,笔者在牛客网上遇到了一道 NC93 LRU(最近最少使用)算法题。虽然这道题并不算难,但它却巧妙地考查了我们对 Map 数据结构的理解。在解决这道题目的过程中,笔者也深切地感受到自己对 Map 的掌握还有待提升,因此花费了一番时间深入钻研。
什么是 LRU 缓存?
LRU 缓存(Least Recently Used Cache)是一种广泛应用于计算机系统中的缓存机制。它的主要思想是:当缓存空间不足时,将最长时间未被使用的元素(即最近最少使用的元素)从缓存中移除,为新元素腾出空间。
NC93 算法题解
NC93 算法题要求我们实现一个 LRU 缓存结构,支持以下操作:
set(key, value)
:将一个键值对插入缓存中。get(key)
:获取缓存中指定键对应的值。
题解思路
为了实现 LRU 缓存,我们可以使用哈希表(Map)来存储键值对,同时使用一个双向链表来维护缓存中的元素顺序。具体来说,哈希表中的键对应着缓存中的元素,而值对应着该元素在链表中的位置。当进行 set
操作时,如果键已存在于哈希表中,则更新其值并将其移动到链表头部;如果键不存在,则将其插入哈希表中并添加到链表头部。当进行 get
操作时,直接从哈希表中获取元素并将其移动到链表头部。
代码示例
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class LRUCache {
private int capacity;
private Map<Integer, Integer> cache;
private DoublyLinkedList list;
public LRUCache(int capacity) {
this.capacity = capacity;
cache = new LinkedHashMap<>();
list = new DoublyLinkedList();
}
public int get(int key) {
if (!cache.containsKey(key)) {
return -1;
}
list.moveToHead(cache.get(key));
return cache.get(key);
}
public void set(int key, int value) {
if (cache.containsKey(key)) {
list.moveToHead(cache.get(key));
cache.put(key, value);
} else {
if (cache.size() == capacity) {
int tailKey = list.removeTail();
cache.remove(tailKey);
}
list.addToHead(key);
cache.put(key, value);
}
}
private class DoublyLinkedList {
private Node head;
private Node tail;
public void addToHead(int key) {
Node newHead = new Node(key);
if (head == null) {
head = newHead;
tail = newHead;
} else {
newHead.next = head;
head.prev = newHead;
head = newHead;
}
}
public void moveToHead(int key) {
Node node = findNode(key);
if (node == null) {
return;
}
if (node == head) {
return;
}
if (node == tail) {
tail = tail.prev;
tail.next = null;
} else {
node.prev.next = node.next;
node.next.prev = node.prev;
}
addToHead(key);
}
public int removeTail() {
if (tail == null) {
return -1;
}
int key = tail.key;
tail = tail.prev;
if (tail != null) {
tail.next = null;
} else {
head = null;
}
return key;
}
private Node findNode(int key) {
Node curr = head;
while (curr != null) {
if (curr.key == key) {
return curr;
}
curr = curr.next;
}
return null;
}
private class Node {
private int key;
private Node prev;
private Node next;
public Node(int key) {
this.key = key;
}
}
}
}
总结
通过对 NC93 LRU 缓存设计算法题的深入分析,我们不仅理解了 LRU 缓存的原理,更重要的是领会了 Map 数据结构在算法实现中的巧妙应用。希望这篇文章能为读者带来启发,帮助大家更好地理解算法题并提升自己的编码能力。