【LeetCode刷题-链表】--146.LRU缓存

146.LRU缓存

方法一:哈希表+双向链表

使用一个哈希表和一个双向链表维护所有在缓存中的键值对

  • 双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久使用的
  • 哈希表即为普通的哈希映射,通过缓存数据的键映射到其在双向链表中的位置

这样以来,我们首先使用哈希表进行定位,找出缓存项在双向链表中的位置,随后将其移动到双向链表的头部,即可在O(1)的时间内完成get或者put操作,具体方法如下:

  • 对于get操作,首先判断key是否存在

    • 如果key不存在,则返回-1
    • 如果key存在,则key对应的节点是最近被使用的节点,通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部, 最后返回该节点的值
  • 对于put操作,首先判断key是否存在

    • 如果key不存在,使用key和value创建一个新的节点,在双向链表的头部添加该节点,并将key和该节点添加进哈希表中,然后判断双向链表的节点数是否超出容量,如果超出容量,则删除双向链表的尾部节点,并删除哈希表中对应的项
    • 如果key存在,则与get操作类似,先通过哈希表定位,再将对应的节点的值更新为value,并将该节点移到双向链表的头部
java 复制代码
class LRUCache {
    class DLinkedNode{
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;
        public DLinkedNode(){}
        public DLinkedNode(int _ket,int _value){
            key = _ket;
            value = _value;
        }
    }
    private Map<Integer,DLinkedNode> cache = new HashMap<Integer,DLinkedNode>();
    private int size;
    private int capacity;
    private DLinkedNode head,tail;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        //使用伪头部和伪尾部节点
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if(node == null){
            return -1;
        }
        //如果key存在,先通过哈希表定位,再移到头部
        moveToHead(node);
        return node.value;
    }
    
    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if(node == null){
            //如果key不存在,创建一个新节点
            DLinkedNode newNode = new DLinkedNode(key,value);
            //添加进哈希表
            cache.put(key,newNode);
            //添加至双向链表的头部
            addToHead(newNode);
            ++size;
            if(size > capacity){
                //如果超出容量,删除双向链表的尾部节点
                DLinkedNode tail = removeTail();
                //删除哈希表中对应的项
                cache.remove(tail.key);
                --size;
            }
        }
        else{
            //如果key存在,先通过哈希表定位,再修改value,并移到头部
            node.value = value;
            moveToHead(node);
        }
    }

    private void addToHead(DLinkedNode node){
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }
    private void removeNode(DLinkedNode node){
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
    private void moveToHead(DLinkedNode node){
        removeNode(node);
        addToHead(node);
    }

    private DLinkedNode removeTail(){
        DLinkedNode res = tail.prev;
        removeNode(res);
        return res;
    }

}

/**
 * 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 天前
【LeetCode刷题日记】47.全排列Ⅱ
java·开发语言·算法·leetcode
Navigator_Z1 天前
LeetCode //C - 1095. Find in Mountain Array
c语言·算法·leetcode
zzz_23681 天前
【Java基础】链表的七十二变——从LRU缓存到手写浏览器前进后退
java·链表·缓存
Irissgwe1 天前
顺序表和链表
数据结构·c++·链表·c·顺序表·线性表
玖玥拾1 天前
C/C++ 数据结构(四)链表与STL容器
c语言·数据结构·c++·链表·stl库
满怀冰雪1 天前
第15篇-链表基础-反转链表-合并链表与快慢指针
java·算法·链表
玖玥拾1 天前
C/C++ 数据结构(一)基础概念、线性表链表
c语言·数据结构·c++·链表
暖阳华笺1 天前
【数据结构与算法】哈希专题
数据结构·c++·算法·leetcode·哈希算法
LuminousCPP1 天前
数据结构 - 单链表第二篇:单链表进阶操作
c语言·数据结构·笔记·链表
玖玥拾1 天前
C/C++ 数据结构(三)链表核心算法
c语言·数据结构·c++·链表