class DLinkedList { int key; int value; int expireStep; DLinkedList pre, next;
public DLinkedList(int key, int value, int expireStep) { this.key = key; this.value = value; this.expireStep = expireStep; } }
public class ExpirableLRUCache { private int capacity; private int currentStep = 0; private DLinkedList head, tail; private Map<Integer, DLinkedList> map = new HashMap<>();
public StepLRUCache(int capacity) { this.capacity = capacity; head = new DLinkedList(-1, -1, -1); tail = new DLinkedList(-1, -1, -1); head.next = tail; tail.pre = head; }
private void removeNode(DLinkedList node) { node.pre.next = node.next; node.next.pre = node.pre; map.remove(node.key); }
private void addToHead(DLinkedList node) { node.next = head.next; node.pre = head; head.next.pre = node; head.next = node; map.put(node.key, node); }
private void moveToHead(DLinkedList node) { removeNode(node); addToHead(node); }
private void removeTail() { DLinkedList node = tail.pre; if (node != head) { removeNode(node); } }
private void removeExpiredNodes() { DLinkedList cur = tail.pre; while (cur != head) { DLinkedList pre = cur.pre; if (cur.expireStep <= currentStep) { removeNode(cur); } cur = pre; } }
public int get(int key) { currentStep++; removeExpiredNodes();
if (!map.containsKey(key)) return -1;
DLinkedList node = map.get(key); moveToHead(node); return node.value; }
public void put(int key, int value, int ttlSteps) { currentStep++; removeExpiredNodes();
if (map.containsKey(key)) { DLinkedList node = map.get(key); node.value = value; node.expireStep = currentStep + ttlSteps; moveToHead(node); } else { DLinkedList node = new DLinkedList(key, value, currentStep + ttlSteps); addToHead(node); if (map.size() > capacity) { removeTail(); } } } }
|