题目
题解(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);
}
}