leetcode146(LRU缓存机制 ) | 刷题打卡

238 阅读2分钟

掘金团队号上线,助你 Offer 临门! 点击 查看详情

一、题目描述:
运用你掌握的数据结构,实现一个LRU(最近最少使用)缓存机制.
LRU缓存的实现:

  • LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果key对应的value在缓存中则返回value,否则返回-1;
  • void put(int key,int value) 如果key对应的value已经存在,则替换该value,如果不存在,则插入该键值对到缓存中,如果缓存达到了存储上限,则删除最久未使用的元素,为新元素的存储腾开空间
  • 要求get和put方法的时间复杂度控制在O(1)

二、思路分析: LRU缓存常规思路就是使用链表的方式实现,但是常规链表实现的缓存的查询复杂度为O(n),需要遍历链表,所以我们需要一个Hash映射表做一个<键-链表节点的映射>,这样查询的复杂度就是O(1)了。对应Java中实现的类就是LinkedHashMap,查看源码即可

三、AC代码:

class LRUCache {
    //Java中的LinkedHashMap = 双向链表+hashMap,实现O(1)复杂度
    //双向链表+HashMap
    class DLinkNode {
        DLinkNode prev ;
        DLinkNode next;
        int key;
        int value;
        public DLinkNode(){}
        public DLinkNode(int key,int value){this.key = key;this.value = value;}
    }
    //hash表
    Map<Integer,DLinkNode> map ;
    //一个空头,一个空尾节点
    DLinkNode head;
    DLinkNode tail;
    //容量
    private int capacity ;
    //实时数量
    private int size;
    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        this.head  = new DLinkNode();
        this.tail = new DLinkNode();
        map  = new HashMap(capacity);
        this.head.next = tail;
        this.tail.prev = head;
    }
    
    public int get(int key) {
        DLinkNode valueNode = map.get(key);
        if(valueNode == null){
            return -1;
        }
        removeNode(valueNode);
        addHead(valueNode);
        return valueNode.value;
    }
    
    public void put(int key, int value) {
        DLinkNode valueNode = map.get(key);
        //不存在该值时
        if(valueNode == null){
            if(this.size >= this.capacity){
                //从链表中删除
                DLinkNode removedNode = removeOldest();
                //从HashMap中删除
                map.remove(removedNode.key);
                --size;
            }
            DLinkNode temp = new DLinkNode(key,value);
            addHead(temp);
            map.put(key,temp);
            ++size;
        }else{
            //存在该值时,更新HashMap中的值
            valueNode.value = value;
            //移动该节点到头部
            removeNode(valueNode);
            addHead(valueNode);
        }
    }

    //删除链表中的某一个节点O(1)
    private void removeNode(DLinkNode valueNode){
        valueNode.prev.next = valueNode.next;
        valueNode.next.prev = valueNode.prev;
    }

    //删除最老的元素
    private DLinkNode removeOldest(){
        DLinkNode oldest = this.tail.prev;
        removeNode(oldest);
        return oldest;
    }

    //将一个节点添加到链表的头部O(1)
    private void addHead(DLinkNode valueNode){
        this.head.next.prev = valueNode;
        valueNode.next = this.head.next;
        valueNode.prev = this.head;
        this.head.next = valueNode;
    }

}

四、总结