146. LRU缓存机制(java)

146. LRU缓存机制

题目描述

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶:

你是否可以在 O(1) 时间复杂度内完成这两种操作?

示例:

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


题解:双向链表+哈希

思路
  1. 双向链表及哈希表所需的节点类
  2. 构建双向链表,实现 addFirst、remove、removeLast、size 四个api
  3. 实现LRU
    1. get :判断是否已存在,不存在再调用put将数据提前
    2. put:
      1. 存在节点,删除旧的,新的插到头部
      2. 不存在:若缓存已满,删除最后一个。再加入数据,否则直接加入数据。

//创建双链表,哈希表所需结点
class Node{
    int key,val;
    public Node pre,next;
    public Node(int k,int v){
        this.key = k;
        this.val = v;
    }
}

class DoubleList{
    private Node head,tail; //头尾虚结点
    private int size; //元素数

    public DoubleList(){
        head=new Node(0,0);
        tail=new Node(0,0);
        head.next = tail;
        tail.pre = head;
        size=0;
    }
    //在链表头部添加节点x
    public void addFirst(Node x){
        x.next = head.next;
        x.pre =head;
        head.next.pre = x;
        head.next = x;jie
        size++;
    }
    //删除链表中的x结点(x一定存在)
    public void remove(Node x){
        x.pre.next=x.next;
        x.next.pre = x.pre;
        size--;
    }
    //删除最后一个节点并返回
    public Node removeLast(){
        if(tail.pre==head) return null;
        Node last = tail.pre;
        remove(last);
        return last;
    }
    public int size(){ return size;}
}
class LRUCache {
    private Map<Integer, Node> map;
    private DoubleList cache; 
    private int cap;

    public LRUCache(int capacity) {
        this.cap = capacity; //最大容量
        map = new HashMap<>();
        cache = new DoubleList(); 
    }
    
    public int get(int key) {
        if(!map.containsKey(key)) return -1;
        int val = map.get(key).val;
        //利用put方法将该数据提前
        put(key,val);
        return val;
    }
    
    public void put(int key, int value) {
        //制作新节点x
        Node x = new Node(key,value);
        if(map.containsKey(key)){
            //删除旧节点
            cache.remove(map.get(key));
            //添加到头部
            cache.addFirst(x);
            //更新map中的值
            map.put(key,x);
        }
        else{
            if(cache.size()==cap){
                //删除最后一个数据
                Node last = cache.removeLast();
                //移除map中对应的键值对
                map.remove(last.key);//需要对应的key,所以cache存储需要用Node,而不是只存value
            }
            //将新节点直接添加头部
            cache.addFirst(x);
            //更新map
            map.put(key,x);
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值