【每日一题Day336】LC146最近最少使用缓存 | 哈希表+链表

简介: 【每日一题Day336】LC146最近最少使用缓存 | 哈希表+链表

最近最少使用缓存【LC146】

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存

int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。

void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.

Implement the LRUCache class:

LRUCache(int capacity) Initialize the LRU cache with positive size capacity.

int get(int key) Return the value of the key if the key exists, otherwise return -1.

void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.

The functions get and put must each run in O(1) average time complexity.

思路

使用HashMap存储key和value

使用双链表记录最近使用的元素先后顺序:每次访问(get或者put)一个元素,都将其移到链表的末尾,那么当元素数量超过容量时,每次要移除的都是链表的第一个元素

实现

map集合的key为key,value为双链表的节点,节点存储key和value

get函数

map中存在key,将该节点移动到末尾

map中不存在key,直接返回-1

put函数

map中存在key,更新key对应的节点的value,并将其移动到末尾

map中不存在key,判断map的size是否大于等于容量

是,移除头结点的下一个节点后将该节点放入map,并放入链表末尾

否,直接将该节点放入map,并放入链表末尾

因此需要编写辅助函数insertToTail,deleteNode,moveToTail

class LRUCache {
    Map<Integer,ListNode> map;
    int capacity;
    ListNode head;
    ListNode tail;
    public LRUCache(int capacity) {
        this.map = new HashMap<>();
        this.capacity = capacity;
        head = new ListNode(-1, -1);
        tail = new ListNode(-1, -1);
        head.next = tail;
        tail.prev = head;
    }
    public int get(int key) {
        ListNode listNode = map.get(key);
        if (listNode == null){
            return -1;
        }
        moveToTail(listNode,listNode.value);        
        return listNode.value;
    }
    public void put(int key, int value) {
        if (map.containsKey(key)){
            moveToTail(map.get(key),value);
        }else{
            if (map.size() == capacity){
                map.remove(head.next.key);
                deleteNode(head.next);               
            }
            ListNode newNode = new ListNode(key,value);
            map.put(key,newNode);
            insertTotail(newNode);
        }
    }
    public void deleteNode(ListNode listNode){
        listNode.prev.next = listNode.next;
        listNode.next.prev = listNode.prev;
    }
    public void moveToTail(ListNode listNode, int newValue){ 
        deleteNode(listNode);
        listNode.value = newValue;
        insertTotail(listNode);
    }
    public void insertTotail (ListNode listNode){
        tail.prev.next = listNode;
        listNode.prev = tail.prev;
        listNode.next = tail;
        tail.prev = listNode;
    }
}
class ListNode{
    public int key;
    public int value;
    public ListNode next;
    public ListNode prev;
    public ListNode(int k, int v){
        key = k;
        value = v;
    }
}
/**
 * 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);
 */


目录
相关文章
|
6月前
|
存储
LeetCode刷题---817. 链表组件(哈希表)
LeetCode刷题---817. 链表组件(哈希表)
|
6月前
|
存储 缓存 算法
【每日一题Day337】LC460LFU 缓存 | 双链表+哈希表
【每日一题Day337】LC460LFU 缓存 | 双链表+哈希表
99 0
|
5月前
|
存储 缓存 算法
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
49 0
|
5月前
|
存储 算法 数据可视化
深入解析力扣160题:相交链表的解决方法(哈希表法与双指针法详细图解)
深入解析力扣160题:相交链表的解决方法(哈希表法与双指针法详细图解)
|
6月前
|
算法 索引
LeetCode刷题--- 138. 复制带随机指针的链表(哈希表+迭代)
LeetCode刷题--- 138. 复制带随机指针的链表(哈希表+迭代)
|
6月前
|
索引
【每日一题Day281】LC142链表 Ⅱ| 快慢指针 哈希表
【每日一题Day281】LC142链表 Ⅱ| 快慢指针 哈希表
39 0
|
6月前
|
存储 索引
【每日一题Day280】LC141环形链表 | 快慢指针 哈希表
【每日一题Day280】LC141环形链表 | 快慢指针 哈希表
34 0
|
6月前
【每日一题Day234】LC1171从链表中删去总和值为零的连续节点 | 链表模拟 哈希表+前缀和
【每日一题Day234】LC1171从链表中删去总和值为零的连续节点 | 链表模拟 哈希表+前缀和
40 0
|
1月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
77 6
|
10天前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题

热门文章

最新文章

下一篇
无影云桌面