【LeetCode-中等题】146. LRU 缓存

这篇具有很好参考价值的文章主要介绍了【LeetCode-中等题】146. LRU 缓存。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目

LRU缓存是什么:LRU缓存机制,你想知道的这里都有
实现 LRU 缓存算法
【LeetCode-中等题】146. LRU 缓存,力扣,# 中等题,leetcode,缓存,算法

方法一:直接继承LinkedHashMap调用api

class LRUCache extends LinkedHashMap<Integer, Integer>{
    private int capacity;
    
    public LRUCache(int capacity) {
        super(capacity, 0.75F, true);
        this.capacity = capacity;
    }

    public int get(int key) {
        return super.getOrDefault(key, -1);
    }

    public void put(int key, int value) {
        super.put(key, value);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
        return size() > capacity; 
    }
}

方法二:自定义LinkedHashMap = HashMap + ListNode == LinkedHashMap

map —>key存 integer value存链表节点
ListNode 存 next 和prev 引用 以及 存 key 和value 具体值
【LeetCode-中等题】146. LRU 缓存,力扣,# 中等题,leetcode,缓存,算法

图解:官方图解

步骤:

  1. 定义一个自定义的双向链表节点类 DLinkedNode,该类包含 key 和 value 字段,并且具有 prev 和 next 指针用于构建双向链表。
  2. 创建一个哈希表 cache 用于存储键值对,其中键为索引,值为双向链表的节点。
  3. 定义变量 size 表示当前哈希表中已存储的键值对数量。
  4. 定义变量 capacity 表示哈希表的容量。
  5. 创建伪头部节点 head 和伪尾部节点 tail,并将它们连接起来形成一个空的双向链表。

方法列表:文章来源地址https://www.toymoban.com/news/detail-688066.html

  1. 构造函数 LRUCache(int capacity):初始化缓存的容量,同时初始化 size、capacity、head 和 tail 变量。
  2. int get(int key):获取指定键对应的值,如果键不存在则返回 -1。如果键存在,则通过哈希表定位到双向链表中的节点,并将该节点移到链表头部,然后返回节点的值。
  3. void put(int key, int value):插入或更新键值对。如果键已存在,则更新对应的值,并将对应的节点移到链表头部。如果键不存在,则创建一个新的节点,添加到哈希表和链表头部。如果插入后超出容量,则删除尾部节点,并从哈希表中移除对应的记录。
  4. DLinkedNode removeTail():在超出容量时删除尾部节点,并返回删除的尾部节点。
  5. void addToHead(DLinkedNode newNode):将指定节点添加到伪头部节点的后面。
  6. void moveToHead(DLinkedNode node):将指定节点移到伪头部节点的后面,即删除原位置的节点并将其添加到伪头部节点后面。
  7. void removeNode(DLinkedNode node):从双向链表中删除指定节点。
class LRUCache {
    /**
     * 自定义双向链表
     */
    class DLinkedNode {
        int key;
        int value;
        DLinkedNode prev;
        DLinkedNode next;
        public DLinkedNode() {}
        public DLinkedNode(int _key, int _value) {key = _key; value = _value;}
    }

    private Map<Integer, DLinkedNode> cache = new HashMap<Integer, DLinkedNode>();//定义哈希表  key为索引  value为双向链表的节点
    private int size;//map的存值后的大小
    private int capacity;//map 的容量
    private DLinkedNode head, tail; //定义双向链表的伪头部和伪尾部节点



    /**
     * 定义初始容量方法
     * @param capacity
     */
    public LRUCache(int capacity) { //定义初始容量方法
        this.size = 0;
        this.capacity = capacity;
        // 使用伪头部和伪尾部节点
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;

    }

    /**
     * 依据key获取对应value
     * @param key
     * @return
     */
    public int get(int key) {
        DLinkedNode node = cache.get(key);//获取key对应的链表节点
        if (node == null) {  //如果node为null  说明key没有对应的value值
            return  -1;
        }
        // 如果 key 存在,先通过哈希表定位,再移到头部
        moveToHead(node);//将待get的节点移动到头部,再返回节点的值
        return node.value;
    }

    /**
     * 往哈希表中添加元素的方法
     * @param key
     * @param value
     */
    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);//put时  先获取这个key的位置有没有值  有?覆盖原值  没有就插入进去
        if (node == null) {// 如果 key 不存在,创建一个新的节点
            DLinkedNode newNode = new DLinkedNode(key, value);
            // 添加进哈希表
            cache.put(key, newNode);
            // 添加至双向链表的头部
            addToHead(newNode);
            size++; //map集合元素+1
            if (size > capacity) {
                // 如果超出容量,删除双向链表的尾部节点
                DLinkedNode tail = removeTail(); //从链表中把尾结点删除,并且方法得返回这个节点  方便map把这个节点对应的元素remove掉
                cache.remove(tail.key);
                size--;
            }
        }else{// 如果 key 存在,覆盖原值,并移到链表头部
            node.value = value;
            moveToHead(node);
        }
    }

    /**
     * 超出容量时删除尾部节点 并且返回尾部节点  方便对清除map中的残留
     * @return
     */
    private DLinkedNode removeTail() {
        DLinkedNode tailNode = tail.prev;//获取伪尾节点的前一个节点  即链表真实的尾节点
        removeNode(tailNode);
        return tailNode;//返回尾部节点  方便对清除map中的残留
    }


    /**
     * 新增节点时节点添加到伪头结点后面的位置
     * @param newNode
     */
    private void addToHead(DLinkedNode newNode) {
        newNode.prev = head;
        newNode.next = head.next;
        head.next.prev = newNode;
        head.next = newNode;
    }

    /**
     * get方法获取key对应value
     * put方法出现重复key时  覆盖原value
     * 这两种情况都会触发将操作的节点移动到伪首节点的后面
     * @param node
     */
    private void moveToHead(DLinkedNode node) {
        //删除原位置的自己
        removeNode(node);
        //将自己添加到伪首节点的后面
        addToHead(node);//调用上面写过的将节点添加到伪首节点的后面
    }

    /**
     * 删除node节点
     * @param node
     */
    private void removeNode(DLinkedNode node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
        node.next = null;
        node.prev = null;
    }

}

到了这里,关于【LeetCode-中等题】146. LRU 缓存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

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

    方法一:哈希表+双向链表 使用一个哈希表和一个双向链表维护所有在缓存中的键值对 双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久使用的 哈希表即为普通的哈希映射,通过缓存数据的键映射到其在双向链表中的

    2024年02月05日
    浏览(34)
  • leetcode做题笔记146. LRU 缓存

    请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。 实现  LRUCache  类: LRUCache(int capacity)  以  正整数  作为容量  capacity  初始化 LRU 缓存 int get(int key)  如果  key  存在于缓存中,则返回的值,否则返回  -1  。 void put(int key, int value)  如果

    2024年02月07日
    浏览(29)
  • Leetcode 146. LRU 缓存(Hashmap+双链表)

    请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: ● LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 ● int get(int key) 如果 key 存在于缓存中,则返回的值,否则返回 -1 。 ● void put(int key, int value) 如果 key 已

    2024年02月16日
    浏览(37)
  • 二刷LeetCode--146.LRU缓存(C++版本),必会题目

    本题思路:因为需要记录元素的出入顺序,并且每次访问之后需要将该节点提到最前面,因此需要使用双向链表(单链表不方便删除操作),而为了可以在常量时间复杂度内找到对应的元素,我们需要使用哈希表,将每一个插入的元素在哈希表中进行记录.哈希表的key就是插入的key,而哈希

    2024年02月13日
    浏览(26)
  • 每日两题 / 142. 环形链表 II & 146. LRU 缓存(LeetCode热题100)

    142. 环形链表 II - 力扣(LeetCode) 用哈希记录走过的节点即可 146. LRU 缓存 - 力扣(LeetCode) O ( 1 ) O(1) O ( 1 ) 地查找并修改kv结构,用unordered_map即可解决 问题是题目要求:哈希表容量有限,超出容量时,将删除最久未访问的kv 那么关键就在于:如何用数据结构表示访问的先后顺

    2024年04月16日
    浏览(30)
  • (力扣记录)146. LRU 缓存

    数据类型 :链表 时间复杂度: O(1) 空间复杂度: O(N) 代码实现:

    2024年01月18日
    浏览(30)
  • 146. LRU 缓存

    请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果 key 存在于缓存中,则返回的值,否则返回 -1 。 void put(int key, int value) 如果 key 已经存在,

    2024年02月12日
    浏览(34)
  • LeetCode刷题---LRU缓存

    LRU是Least Recently Used的缩写,即最近最少使用,是一种内存管理算法,也可以用作缓存淘汰策略。 这种算法的核心思想是:如果数据最近被访问过,那么将来被访问的几率也更高。 因此,当内存或缓存容量有限,需要淘汰部分数据时,LRU算法会优先淘汰那些最长时间未被访问

    2024年02月22日
    浏览(27)
  • 【LeetCode力扣】11. 盛最多水的容器 (中等)

      目录 1、题目介绍 2、解题 2.1、解题思路  2.2、图解说明  2.3、解题代码 原题链接: 11. 盛最多水的容器 - 力扣(LeetCode) 示例 2: 提示: n == height.length 2 = n = 105 0 = height[i] = 104 这道题最优的方法就是用双指针,我们可以用指针 left 和指针 right 分别指向数组 height[ ] 的第一

    2024年02月06日
    浏览(36)
  • 【leetcode100-035】【链表/哈希链表】LRU缓存

    【题干】 请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。 实现  LRUCache  类: LRUCache(int capacity)  以  正整数  作为容量  capacity  初始化 LRU 缓存 int get(int key)  如果  key  存在于缓存中,则返回的值,否则返回  -1  。 void put(int key, in

    2024年02月01日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包