Leetcode——146. LRU 缓存机制

题目描述:
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:

  • LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
  • int get(int key):如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value):如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

示例:

输入
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4

分析:
通过分析题目描述,我们可以得出以下几点:

  • 在调用get()方法的时候存储的是键值对,所以我们应该联想到Map
  • 在调用get()/set()方法时,被操作的数据都是最近刚使用的,所以应该把被操作的数据置为优先级最高,具体使用什么方式下面说。

对于以上两点,第一点很容易想到,但是第二点每次把数据操作之后都需要调整它的顺序,一开始我想到队列,队列是先进先出的特性,对尾插入元素,删除从队头删除,因此可以将队头元素看作优先级最低,对尾元素每次都是优先级最高。
但是,它还存在一个问题,就是当有元素重复了,我需要先将该元素从队列删除(此时可能不是队头元素),然后再进行对尾插入,可是队列遍历好像不是很容易实现,比较麻烦。

因此,对于优先级问题,我们采用链表的形式:

  • 头插:链表头元素优先级最高
  • 删除:只需通过指针域就可以进行删除,O(1)
  • 遍历:方便实现

举个例子:就以测试用例为例:[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]],容量为2
执行[1, 1], [2, 2],存储结构如下图所示:
在这里插入图片描述
因此,我们需要自己定义链表节点类:

public class Node{
        public int key;
        public int value;
        public Node next=null;
        public Node pre=null;
        public Node(int key,int value)
        {
            this.key=key;
            this.value=value;
        }
    }

Map数据结构:

  Map<Integer,Node> map=new HashMap<>();

代码实现:

class LRUCache {
    public int  capacity;
    public class Node{
        public int key;
        public int value;
        public Node next=null;
        public Node pre=null;
        public Node(int key,int value)
        {
            this.key=key;
            this.value=value;
        }
    }
    Node head=new Node(-1,-1);
    Node tail=new Node(-1,-1);
    Map<Integer,Node> map=new HashMap<>();
    public LRUCache(int capacity) {
        head.next=tail;
        tail.pre=head;
        this.capacity=capacity;
    }
    
    public int get(int key) {
        //如果该key不在Map中,直接返回-1
        if(!map.containsKey(key))
        {
            return -1;
       
        }else{//如果在map中,删除该节点,再将其头插到链表中
            Node tmp=map.get(key);
            //删除
            tmp.pre.next=tmp.next;
            tmp.next.pre=tmp.pre;
            //头插
            tmp.next=head.next;
            tmp.pre=head;
            head.next=tmp;
            tmp.next.pre=tmp;
            return tmp.value;
        }

    }
    
    public void put(int key, int value) {
        //map中已经存在:删除该节点,再头插
        if(map.containsKey(key))
        {
             //删除
            Node tmp=map.get(key);
             tmp.next.pre=tmp.pre;
            tmp.pre.next=tmp.next;
            map.remove(key);
        }else{//不存在:如果容量已满,将链表尾删除再头插
            //map的元素个数大于等于容量,
            if(map.size()>=capacity)
            {
             //删除
                 Node tmp=tail.pre;
                tail.pre=tmp.pre;
                tmp.pre.next=tail;           
                map.remove(tmp.key);
            }
        }
        Node tmp=new Node(key,value);
        map.put(key,tmp);
        tmp.next=head.next;
        head.next.pre=tmp;
        head.next=tmp;
        tmp.pre=head;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值