LeetCode 146 — LRU 缓存

题目描述

请你设计并实现一个满足 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) 的平均时间复杂度运行。

题目分析

使用双向链表来维护数据,使用 HashMap 实现对 key 的 O(1) 访问.
每次访问一个数据(get 或 put),就把其移动到链表的尾部,而链表头部即是最久未访问的元素。当容量超出设定时(put 时判断),将头部元素在链表和 HashMap 中同步移除。
使用虚拟头结点和尾结点,代码写起来更简单。

Java

public class LruCache {

    private class Node {
        int key;
        int value;
        Node pre;
        Node next;

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

    private HashMap<Integer, Node> map = new HashMap<>();
    // 虚拟头/尾结点
    private Node head = new Node(0, 0); // 旧
    private Node tail = new Node(0, 0); // 新
    private int capacity;

    public LruCache(int capacity) {
        this.capacity = capacity;
        head.next = tail;
        tail.pre = head;
    }

    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }

        Node node = map.get(key);
        moveToTail(node);
        return node.value;
    }

    public void put(int key, int value) {
        Node node;
        if (map.containsKey(key)) {
            node = map.get(key);
            node.value = value;
        } else {
            node = new Node(key, value);
            map.put(key, node);
        }
        moveToTail(node);
        if (map.size() > capacity) {
            removeEldest();
        }
    }

    private void moveToTail(Node node) {
        Node pre = node.pre;
        Node next = node.next;
        if (pre != null) {
            pre.next = next;
            next.pre = pre;
        }
        tail.pre.next = node;
        node.pre = tail.pre;
        node.next = tail;
        tail.pre = node;
    }

    private void removeEldest() {
        map.remove(head.next.key);
        head.next = head.next.next;
        head.next.pre = head;
    }
}

Kotlin

class LruCache(var capacity: Int) {

    private val map = HashMap<Int, Node>()
    private val head = Node(0, 0) // 旧
    private val tail = Node(0, 0) // 新

    init {
        head.next = tail
        tail.pre = head
    }

    fun get(key: Int): Int {
        if (!map.containsKey(key)) {
            return -1
        }
        val node = map[key]!!
        moveToTail(node)
        return node.value
    }

    fun put(key: Int, value: Int) {
        if (map.containsKey(key)) {
            val node = map[key]!!
            node.value = value
            moveToTail(node)
        } else {
            val node = Node(key, value)
            map[key] = node
            moveToTail(node)
            if (map.size > capacity) {
                removeEldest()
            }
        }
    }

    private fun moveToTail(node: Node) {
        if (node.pre != null) {
            val pre = node.pre
            val next = node.next
            pre?.next = next
            next?.pre = pre
        }

        tail.pre?.next = node
        node.pre = tail.pre
        node.next = tail
        tail.pre = node
    }

    private fun removeEldest() {
        val node = head.next
        head.next = node?.next
        head.next?.pre = head
        map.remove(node?.key!!)
    }

    private data class Node(var key: Int, var value: Int, var pre: Node? = null, var next: Node? = null)
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部