带过期时间的LRU(可运行)

import java.util.*;

class Node {
    public Integer key;
    public Integer value;
    public Long timeStamp;

    public Node(Integer key, Integer value, Long timeStamp) {
        this.key = key;
        this.value = value;
        this.timeStamp = timeStamp;
    }
}

class LRUCache {
    private Map<Integer, Node> map;
    private int capacity;

    public LRUCache(int capacity) {
        map = new LinkedHashMap<>();
        this.capacity = capacity;
    }

    public int get(int key) {
        Node node = map.get(key);
        // key 不存在
        if (node == null) {
            return -1;
        }
        // key 过期(懒删除策略)
        if (isExpire(node)) {
            map.remove(key);
            return -1;
        }
        map.remove(key);
        map.put(key, node);
        return node.value;
    }

    public void put(int key, int value, Long timeStamp) {
        Node node = map.get(key);
        if (node == null) {  // key 不存在
            node = new Node(key, value, timeStamp);
            if (map.size() < capacity) {  // 有额外空间
                map.put(key, node);
            } else {  // 没有额外空间
                // 先尝试移除过期key
                removeExpireNodes();
                // 如果空间还是不足,移除最老的key
                if (map.size() >= capacity) {
                    map.remove(map.keySet().iterator().next());
                }
                map.put(key, node);
            }
        } else {  // key 存在
            map.remove(key);
            node = new Node(key, value, timeStamp);
            map.put(key, node);
        }
    }

    private void removeExpireNodes() {
        for (Node node : map.values()) {
            if (isExpire(node)) {
                map.remove(node.key);
            }
        }
    }

    private boolean isExpire(Node node) {
        if (node.timeStamp == null) {  // 没有时间戳表示永久不过期
            return false;
        }
        return System.currentTimeMillis() > node.timeStamp;
    }

}

class LRUTTL {
    public static void main(String[] args) {
        LRUCache cache = new LRUCache(2);

        cache.put(1, 10, null);
        cache.put(2, 20, null);
        System.out.println(cache.get(1));  // 10
        cache.put(3, 30, null);
        System.out.println(cache.get(2));  // -1

        cache.put(4, 40, System.currentTimeMillis() + 1000);

        try {
            System.out.println(cache.get(1));  // -1
            Thread.sleep(1500);
            System.out.println(cache.get(3));  // 30
            System.out.println(cache.get(4));  // -1
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }
}

优化点:可以维护一个map结构存储<最小过期时间,节点数量>来判断当前LinkedList中是否存在已经过期的node,可以一定程度地减少 removeExpireNodes 的调用次数
全部评论

相关推荐

一面&nbsp;1.&nbsp;介绍实习2.&nbsp;开始追问实习,实习中第一个功能的实现有没有其他替换的方式3.&nbsp;实习中第二个功能,为什么要这么存储(这里被问懵了,太久没面试),然后感觉越描越黑,就跳过了4.&nbsp;看你用过&nbsp;mysql,你来介绍一下mysql吧,我这里就介绍了介绍存储引擎,索引,事务。这里追问了一下事务5.&nbsp;还用过什么存储,简单说了一下&nbsp;redis6.&nbsp;做题,两道都挺简单,一道语法题,我以为这里有坑,想了半天怎么优化,面试官说没有优化的地方了。另一道是一个滑动窗口7.&nbsp;简单介绍了一下业务二面1.&nbsp;先介绍实习,然后拷打实习2.&nbsp;追问了很多底层:美团消息队列mafka延迟消息底层是啥,吞吐量为啥高。这些我不知道,我就往kafka和rocketmq靠了靠,说了一下这两个相关实现是啥。3.&nbsp;追问了一下&nbsp;kafka&nbsp;顺序写的底层(没回答上来4.&nbsp;问限流算法,美团的怎么实现的(我怎么知道。。)我说可能是令牌桶,让我介绍如何实现分布式限流。我说&nbsp;redis,然后追问扛不住怎么办,没回答上来(其实和leaf分布式id生成差不多,做一个本地缓存,一次性申请一批令牌,buffer&nbsp;机制)5.&nbsp;redis&nbsp;过期删除策略,缓存淘汰策略6.&nbsp;做题,一道mid太久没面试了,最近一个月基本没怎么看八股,二面回答的稀烂,感觉是挂了。
查看8道真题和解析
点赞 评论 收藏
分享
评论
2
21
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务