返回

LRU 缓存机制 —— 你的 Java 代码过关了吗?

后端

  • `

  • `

LRU 缓存是什么?

最近最少使用 (LRU) 缓存是一种用于存储数据的缓存机制。它遵循这样一个原则:当缓存已满时,最近最少使用的项目将被移除,为新项目腾出空间。这使得 LRU 缓存非常适合存储经常访问的数据,因为它们更有可能在不久的将来再次被访问。

在 LeetCode 中,146. LRU 缓存是经典问题之一。它要求你实现一个 LRUCache 类,提供以下方法:

class LRUCache {
    int capacity;
    HashMap<Integer, Node> map = new HashMap<>();
    Node head = new Node(0, 0);
    Node tail = new Node(0, 0);

    public LRUCache(int capacity) {
        this.capacity = capacity;
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            removeNode(node);
            addNode(node);
            return node.value;
        }
        return -1;
    }

    public void put(int key, int value) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            removeNode(node);
            node.value = value;
            addNode(node);
        } else {
            Node node = new Node(key, value);
            map.put(key, node);
            addNode(node);
            if (map.size() > capacity) {
                map.remove(tail.prev.key);
                removeNode(tail.prev);
            }
        }
    }

    private void removeNode(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void addNode(Node node) {
        node.next = head.next;
        head.next = node;
        node.next.prev = node;
        node.prev = head;
    }

    class Node {
        int key;
        int value;
        Node prev;
        Node next;

        public Node(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }
}

实现 LRU 缓存的思路

在 Java 中实现 LRU 缓存,首先需要一个数据结构来存储缓存项。这里使用了一个双向链表,链表中的节点表示缓存项,每个节点包含一个键和一个值。双向链表允许我们轻松地插入和删除节点,这对于 LRU 缓存非常重要。

为了实现 LRU 缓存的功能,我们需要维护一个哈希表,哈希表的键是缓存项的键,哈希表的值是缓存项在双向链表中的节点。这允许我们快速地查找缓存项并更新其位置。

当我们向缓存中添加一个新的项时,如果缓存已满,我们需要删除最不常用的项。我们使用双向链表来实现这一点。当我们添加一个新的项时,我们将它添加到链表的头部。当缓存已满时,我们将链表尾部的项删除。

当我们从缓存中获取一个项时,如果该项存在,我们将它从链表中删除并将其添加到链表的头部。这确保了该项在链表中的位置总是最新的。

复杂度分析

LRUCache 的时间复杂度主要取决于底层数据结构的实现。在我们的实现中,我们使用了一个双向链表和一个哈希表。

查找和更新操作的时间复杂度为 O(1),因为我们可以直接通过哈希表找到对应的节点。

添加和删除操作的时间复杂度为 O(1),因为我们只需要修改链表的头部或尾部即可。

总结

LRU 缓存是一种非常重要的计算机算法,它广泛应用于各种系统中。在本文中,我们提供了 LRU 缓存的详细 Java 实现,结合代码分析和示例,帮助你理解和掌握该算法。