LRU java实现避坑:你是不是也因为这个问题debug了一小时!

起因

秋招前练习大厂高频面试题——手撕LRU,之前写过知道双向链表+HashMap的方式能写出来,但各种链表操作属实麻烦且易错,面试场合还会紧张更加提高错误率,就想着有没什么简单点的想法。脑子一抽想着用双端队列Deque写,结果力扣的用例一直没法全过!

LRU题干

(摘自leetcode-面试题 16.25. LRU 缓存)
设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。
它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

// 示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 该操作会使得密钥 2 作废
cache.get(2);       // 返回 -1 (未找到)
cache.put(4, 4);    // 该操作会使得密钥 1 作废
cache.get(1);       // 返回 -1 (未找到)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4

问题分析

下图是力扣中没通过的用例
在这里插入图片描述

原因:当插入key已经存在的节点时(用例中的[2,3]),map.put()会覆盖map中的原键值对(代码中用注释标出),这个没问题,但覆盖之后需要在deque里把访问到的节点移动到队首,这个是双端队列做不到的,队列无法访问除了头尾之外的中间节点!(代码中标红)

java代码

class LRUCache {
    private int size;
    private int capacity;
    Deque<Integer> queue;
    HashMap<Integer,Integer> map = new HashMap<>();

    public LRUCache(int capacity) {
        this.capacity = capacity;
        queue = new LinkedList<>();
        this.size = 0;
    }
    
    public int get(int key) {
        if(map.get(key) == null){
            return -1;
        }else{
            //移到最前
            queue.remove(key);
            queue.addFirst(key);
            return map.get(key);
        }
    }
    
    public void put(int key, int value) {
        //插入
        if(map.get(key)==null){
            map.put(key,value);
            queue.addFirst(key);
            size++;
            //判断容量
            if(size > capacity){
                map.remove(queue.getLast());
                queue.removeLast();
                size--;
            }
        }else{
            //map.put()会覆盖map中的原键值对
            map.put(key,value);
            //这里应该要先删除掉queue中key对应的节点,但deque做不到
            //...
            queue.addFirst(key);
        }
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

结论

老老实实背双向链表的实现方法吧!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值