一. 题目

  • 带过期时间的LRU.

二. 思路

  • 维护双向链表,用于最近最久未使用。

  • 单独node维护k、v、l、r、expireTime。

  • 注意:很多题解,直接put完然后检查是否超限,若超则清除尾巴。但是,双链中可能有已经过期的,且尾巴没过期,其实应该先清理过期,再判断是否超限。

三. 代码

import java.util.HashMap;
import java.util.Map;

public class LRUCache {

    Map<Integer, Node> cache=new HashMap();
    int cap;
    Node head=new Node(0, 0, 0), tail=new Node(0, 0, 0);

    public LRUCache(int capacity) {
        this.cap=capacity;
        head.r=tail;
        tail.l=head;
    }

    public int get(int key) {
        if(!cache.containsKey(key)) return -1;
        Node cur=cache.get(key);
        if(checkAndRemoveExpireNode(cur)) return -1;//过期
        moveToHead(cur);
        return cur.v;
    }

    public void put(int key, int value, long expireTime) {
        Node cur;
        expireTime += System.currentTimeMillis();
        if(cache.containsKey(key)) {//包含直接更新
            cur=cache.get(key);
            cur.v=value;
            cur.expireTime=expireTime;
            moveToHead(cur);
            return;
        }

        if(cache.size()==cap && !removeExpireNodes()) {//到顶,且没有过期的,则删除尾巴
            Node t=tail.l;
            cache.remove(t.k);
            remove(t);
        }

        cur=new Node(key, value, expireTime);
        cache.put(key, cur);
        addHead(cur);
    }

    boolean removeExpireNodes() {
        Node cur=head.r;
        boolean isRemoved=false;
        while(cur!=tail) {
            Node ne=cur.r;
            isRemoved|=checkAndRemoveExpireNode(cur);
            cur=ne;
        }
        return isRemoved;
    }

    boolean checkAndRemoveExpireNode(Node cur) {
        if(cur.expireTime < System.currentTimeMillis()) {
            cache.remove(cur.k);
            remove(cur);
            return true;
        }
        return false;
    }

    void moveToHead(Node cur) {
        remove(cur);
        addHead(cur);
    }

    void remove(Node cur) {
        cur.l.r=cur.r;
        cur.r.l=cur.l;
    }

    void addHead(Node cur) {
        cur.l=head;
        cur.r=head.r;
        head.r.l=cur;
        head.r=cur;
    }

    static class Node {
        int k, v;
        Node l, r;
        long expireTime;

        public Node(int k, int v, long expireTime) {
            this.k=k;
            this.v=v;
            this.expireTime=expireTime;
        }
    }
}