P5528.带过期时间的 LRU 缓存

题目

https://codefun2000.com/ide/P5528?pset=zijie

题解(ACM)

java 复制代码
import java.util.*;
import java.io.*;

class LRUcacheWithTTL {

    class Node {
        int key;
        int value;
        long expiretime;
        Node pre;
        Node next;

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

    HashMap<Integer, Node> map = new HashMap<>();

    // 按过期时间从小到大排序(懒删除:旧版本节点留在堆里,用到时再跳过)
    PriorityQueue<Node> pq = new PriorityQueue<>(
        (a, b) -> Long.compare(a.expiretime, b.expiretime)
    );

    int cap;
    Node head = new Node(-1, -1, -1);
    Node tail = new Node(-1, -1, -1);

    LRUcacheWithTTL(int cap) {
        this.cap = cap;
        head.next = tail;
        tail.pre = head;
    }

    public int get(int k, int time) {
        Node node = map.get(k);
        //不存在
        if (node == null) {
            return -1;
        }

        // 存在,过期
        if (time >= node.expiretime) {
            delete(node);
            return -1;
        }
        //存在,没过期,删node + node后移
        moveToLast(node);
        return node.value;
    }

    public void put(int k, int v, int ttl, int time) {

        if (cap <= 0) return;

        Node node = map.get(k);
        Node newnode = new Node(k, v, (long) ttl + time);

        // 已存在,更新map node pq
        if (node != null) {
            delete(node);//删node
            addLast(newnode);//newnode后移
            map.put(k, newnode);//map
            pq.offer(newnode);//pq放入
            rebuildIfNeeded();//更新
            return;
        }

        // 修改点2:容量满时,清理所有已过期节点
        if (map.size() >= cap) {
            while (!pq.isEmpty()) {
                Node cur = pq.peek();

                // 旧版本节点,跳过
                if (map.get(cur.key) != cur) {
                    pq.poll();
                    continue;
                }

                // 最早过期的节点已过期,继续检查下一个
                if (time >= cur.expiretime) {
                    pq.poll();
                    delete(cur);
                    continue;
                }
                break;
            }
        }

        // 仍然满,淘汰 LRU
        if (map.size() >= cap) {
            delete(head.next);
        }

        map.put(k, newnode);
        addLast(newnode);
        pq.offer(newnode);
        rebuildIfNeeded();
    }

    // 堆里旧节点过多时重建,避免超时/超内存
    private void rebuildIfNeeded() {
        if (pq.size() > 2 * map.size() + 16) {
            pq.clear();
            pq.addAll(map.values());
        }
    }


    private void delete(Node node) {
        remove(node);
        map.remove(node.key);
    }

    private void remove(Node node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }

    private void moveToLast(Node node) {
        remove(node);
        addLast(node);
    }

    private void addLast(Node node) {
        Node last = tail.pre;

        last.next = node;
        node.pre = last;

        node.next = tail;
        tail.pre = node;
    }
}

class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int cap = sc.nextInt();
        int n = sc.nextInt();

        LRUcacheWithTTL lru = new LRUcacheWithTTL(cap);
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < n; i++) {
            String op = sc.next();

            if (op.equals("get")) {
                int a = sc.nextInt();
                int b = sc.nextInt();

                sb.append(lru.get(a, b)).append('\n');

            } else if (op.equals("put")) {
                int a = sc.nextInt();
                int b = sc.nextInt();
                int c = sc.nextInt();
                int d = sc.nextInt();

                lru.put(a, b, c, d);
            }
        }

        System.out.print(sb);
    }
}
相关推荐
SimonKing44 分钟前
DeepSeek 新模型免费白嫖,夯夯夯,赶紧用起来
java·后端·程序员
小徐不徐说1 小时前
C++ 机器视觉入门:从零搭建 AOI 开发环境(OpenCV + CMake)
开发语言·c++·opencv
SabrinaW7111 小时前
基于 C++17 与 RTTR 的注册式对象工厂:配置驱动的动态对象创建
java·前端·数据库
zhangx1234_1 小时前
javaEE 多线程4
java·开发语言
大陈子编程1 小时前
C++ 背包九讲:从入门到精通的动态规划专题
开发语言·c++·动态规划
qq_401700411 小时前
Qt 组播(Multicast)实战详解
开发语言·qt
Sapphire~2 小时前
odoo-095 视图的重写规则(全部重写还是部分改写)
开发语言·javascript·ecmascript
利威尔xu2 小时前
Go GMP 调度器 10 个高频追问:3 个线上故障让 P99 从 80ms 飙到 2s、10 万 goroutine 泄漏
开发语言·后端·面试·性能优化·golang
中电金信2 小时前
从业务调优到分层缓存:DeepSeek V4 Flash的PPU实践
java·开发语言