当前位置: 首页 > news >正文

【每日一题Day337】LC460LFU 缓存 | 双链表+哈希表

LFU 缓存【LC460】

请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。

实现 LFUCache 类:

  • LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象
  • int get(int key) - 如果键 key 存在于缓存中,则获取键的值,否则返回 -1
  • void put(int key, int value) - 如果键 key 已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量 capacity 时,则应该在插入新项之前,移除最不经常使用的项。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近最久未使用 的键。

为了确定最不常使用的键,可以为缓存中的每个键维护一个 使用计数器 。使用计数最小的键是最久未使用的键。

当一个键首次插入到缓存中时,它的使用计数器被设置为 1 (由于 put 操作)。对缓存中的键执行 getput 操作,使用计数器的值将会递增。

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

  • 错误答案

    class LFUCache {// 注意:PriorityQueue要插入(删除)数据,顺序会发生改变,如果仅仅是修改已经稳定队列的值或内容,而不进行插入或者删除,那么,这个顺序是不会变的。// 使用Node存储每个key对应的value,以及该key的操作次数、最近操作时间// 小顶堆存储每个元素, 以使用次数及最近使用时间降序排序int capacity;PriorityQueue<Node> pq;Map<Integer, Node> map;int time;public LFUCache(int capacity) {this.capacity = capacity;this.pq = new PriorityQueue<>((o1, o2) -> o1.freq == o2.freq ? o1.time - o2.time : o1.freq - o2.freq);this.map = new HashMap<>();this.time = 0;}public int get(int key) {if (!map.containsKey(key)) return -1;Node node = map.get(key);node.freq += 1;node.time = time++;return node.val;}public void put(int key, int value) {if (map.containsKey(key)){Node node = map.get(key);node.val = value;node.freq += 1;node.time = time++;}else{Node node = new Node(key, value, time++, 1);if (pq.size() == capacity){Node node1 = pq.poll();map.remove(node1.key);}pq.add(node);map.put(key, node);}}
    }
    class Node{int key;int val;int time;int freq;public Node(){this.freq = 0;}public Node(int key, int val, int time, int freq){this.key = key;this.val = val;this.time = time;this.freq = freq;}
    }/*** Your LFUCache object will be instantiated and called as such:* LFUCache obj = new LFUCache(capacity);* int param_1 = obj.get(key);* obj.put(key,value);*/
    
  • 思路

    • LFU和LRU不同之处
      • LRU移除元素时移除最近最久未使用的元素
      • LFU移除元素时移除使用频率最少最近最久未使用的元素
    • 因此LFU实现可以仿照LRU,使用哈希表记录每个频率下的节点,相同频率下的各个节点以双向链表的形式组织
      • 每次移除元素时移除频率最小的最久未使用的元素
      • 每操作一次元素需要修改节点频率至相应链表
      • 链表的首部存放最新操作的元素
      • 为了快速找到某个节点在链表中的位置,可以使用哈希表存储每个key对应的节点
      • 为了快速找到最小频率,维护一个int变量记录最小频率
  • 实现

    class LFUCache {private static class Node {int key, value, freq = 1; // 新书只读了一次Node prev, next;Node(int key, int value) {this.key = key;this.value = value;}}private final int capacity;private final Map<Integer, Node> keyToNode = new HashMap<>();private final Map<Integer, Node> freqToDummy = new HashMap<>();private int minFreq;public LFUCache(int capacity) {this.capacity = capacity;}public int get(int key) {Node node = getNode(key);return node != null ? node.value : -1;}public void put(int key, int value) {Node node = getNode(key);if (node != null) { // 有这本书node.value = value; // 更新 valuereturn;}if (keyToNode.size() == capacity) { // 书太多了Node dummy = freqToDummy.get(minFreq);Node backNode = dummy.prev; // 最左边那摞书的最下面的书keyToNode.remove(backNode.key);remove(backNode); // 移除if (dummy.prev == dummy) { // 这摞书是空的freqToDummy.remove(minFreq); // 移除空链表}}node = new Node(key, value); // 新书keyToNode.put(key, node);pushFront(1, node); // 放在「看过 1 次」的最上面minFreq = 1;}private Node getNode(int key) {if (!keyToNode.containsKey(key)) { // 没有这本书return null;}Node node = keyToNode.get(key); // 有这本书remove(node); // 把这本书抽出来Node dummy = freqToDummy.get(node.freq);if (dummy.prev == dummy) { // 抽出来后,这摞书是空的freqToDummy.remove(node.freq); // 移除空链表if (minFreq == node.freq) { // 这摞书是最左边的minFreq++;}}pushFront(++node.freq, node); // 放在右边这摞书的最上面return node;}// 创建一个新的双向链表private Node newList() {Node dummy = new Node(0, 0); // 哨兵节点dummy.prev = dummy;dummy.next = dummy;return dummy;}// 在链表头添加一个节点(把一本书放在最上面)private void pushFront(int freq, Node x) {Node dummy = freqToDummy.computeIfAbsent(freq, k -> newList());x.prev = dummy;x.next = dummy.next;x.prev.next = x;x.next.prev = x;}// 删除一个节点(抽出一本书)private void remove(Node x) {x.prev.next = x.next;x.next.prev = x.prev;}
    }

相关文章:

【每日一题Day337】LC460LFU 缓存 | 双链表+哈希表

LFU 缓存【LC460】 请你为 最不经常使用&#xff08;LFU&#xff09;缓存算法设计并实现数据结构。 实现 LFUCache 类&#xff1a; LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象int get(int key) - 如果键 key 存在于缓存中&#xff0c;则获取键的值&#x…...

解决老版本Oracle VirtualBox 此应用无法在此设备上运行问题

问题现象 安装华为eNSP模拟器的时候&#xff0c;对应的Oracle VirtualBox-5.2.26安装的时候提示兼容性问题&#xff0c;无法进行安装&#xff0c;具体版本信息如下&#xff1a; 软件对应版本备注Windows 11专业工作站版22H222621eNSP1.3.00.100 V100R003C00 SPC100终结正式版…...

法规标准-UN R48标准解读

UN R48是做什么的&#xff1f; UN R48全名为关于安装照明和灯光标志装置的车辆认证的统一规定&#xff0c;主要描述了对各类灯具的布置要求及性能要求&#xff1b;其中涉及自动驾驶功能的仅有6.25章节【后方碰撞预警信号】&#xff0c;因此本文仅对此章节进行解读 功能要求 …...

自动化和数字化在 ERP 系统中意味着什么?

毋庸置疑&#xff0c;ERP系统的作用是让工作更轻松。它可以集成流程&#xff0c;提供关键分析&#xff0c;确保你的企业高效运营。这些信息可以提高你的运营效率&#xff0c;并将有限的人力资本重新部署到更有效、更重要的需求上。事实上&#xff0c;自动化和数字化是ERP系统最…...

python nvidia 显卡信息 格式数据

python nvidia 显卡信息 格式数据. def get_gpu_memory():result subprocess.check_output([nvidia-smi, --query-gpupci.bus_id,memory.used,memory.total,memory.free, --formatcsv])# 返回 GPU 的显存使用情况&#xff0c;单位为 Minfo []for t in csv.DictReader(result…...

LeetCode每日一题:1993. 树上的操作(2023.9.23 C++)

目录 1993. 树上的操作 题目描述&#xff1a; 实现代码与解析&#xff1a; 模拟 dfs 原理思路&#xff1a; 1993. 树上的操作 题目描述&#xff1a; 给你一棵 n 个节点的树&#xff0c;编号从 0 到 n - 1 &#xff0c;以父节点数组 parent 的形式给出&#xff0c;其中 p…...

绿色计算产业发展白皮书:2022年OceanBase助力蚂蚁集团减排4392tCO2e

9 月 15 日&#xff0c;绿色计算产业联盟在 2023 世界计算大会期间重磅发布了《绿色计算产业发展白皮书&#xff08;2023 版&#xff09;》。蚂蚁集团作为指导单位之一&#xff0c;联合参与了该白皮书的撰写。 白皮书中指出&#xff0c;落实“双碳”战略&#xff0c;绿色计算已…...

阿里云通义千问14B模型开源!性能超越Llama2等同等尺寸模型

9月25日&#xff0c;阿里云开源通义千问140亿参数模型Qwen-14B及其对话模型Qwen-14B-Chat,免费可商用。Qwen-14B在多个权威评测中超越同等规模模型&#xff0c;部分指标甚至接近Llama2-70B。阿里云此前开源了70亿参数模型Qwen-7B等&#xff0c;一个多月下载量破100万&#xff0…...

两横一纵 | 寅家科技发布10年新征程战略

2023年9月22日&#xff0c;寅家科技“寅路向前”10年新征程战略发布会在上海举办&#xff0c;来自投资领域的东方富海、深创投、高新投等知名投资机构&#xff0c;一汽大众、一汽红旗、奇瑞汽车等主机厂&#xff0c;国家新能源汽车技术创新中心、梅克朗、芯驰科技、思特威等合作…...

二值贝叶斯滤波计算4d毫米波聚类目标动静属性

机器人学中有些问题是二值问题&#xff0c;对于这种二值问题的概率评估问题可以用二值贝叶斯滤波器binary Bayes filter来解决的。比如机器人前方有一个门&#xff0c;机器人想判断这个门是开是关。这个二值状态是固定的&#xff0c;并不会随着测量数据变量的改变而改变。就像门…...

【刷题笔记9.25】LeetCode:相交链表

LeetCode&#xff1a;相交链表 一、题目描述 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 二、分析及代码 方法一&#xff1a;使用哈希Set集合 &#xff08;注意…...

打造本地紧密链接的开源社区——KCC@长沙开源读书会openKylin爱好者沙龙圆满举办...

2023年9月9日&#xff0c;由开源社联合 openKylin 社区举办的 KCC长沙开源读书会&openKylin 爱好者沙龙&#xff0c;在长沙圆满举办。这是 KCC长沙首次正式进入公众视野&#xff0c;开展开源交流活动&#xff0c;也是 openKylin 社区长沙首场线下沙龙。长沙地区及其周边的众…...

Python 笔记03(多线程)

一 打开命令行&#xff0c;查看本机IP windows r 命令行输入&#xff1a;cmd ipconfig 然后查看IPv4的地址&#xff1a;192.168.1*6.1 ipconfig 二 函数式多进程 from multiprocessing import Process import os, timedef func(name):print(进程的ID&#xff1a;, os.g…...

mysql-4:SQL的解析顺序

SQL语句的解析顺序 文章目录 SQL语句的解析顺序编写顺序与解析顺序解析顺序关键字FROMONOUTER JOINWHEREGROUP BYHAVINGSELECTDISTINCTORDER BYLIMIT 解析流程流程分析流程说明WHERE条件解析顺序 编写顺序与解析顺序 编写顺序 SELECT DISTINCT < select_list > FROM &l…...

如何通过优化Read-Retry机制降低SSD读延迟?

近日,小编发现发表于2021论文中,有关于优化Read-Retry机制降低SSD读延迟的研究,小编这里给大家分享一下这篇论文的核心的思路,感兴趣的同学可以,可以在【存储随笔】VX公号后台回复“Optimizing Read-Retry”获取下载链接。 本文中主要基于Charge Trap NAND架构分析。NAND基…...

matlab自动生成FPGA rom源码

1 matlab 源码 close all clear all clci=0:1:(300000-100-1); x=300000./(100+i); x=x./2; x=round(...

消息队列(RabbitMQ+RocketMQ+Kafka)

消息队列是一种应用程序之间通过异步通信进行数据交换的通信模式 消息队列的类型&#xff1a; 点对点&#xff0c;一对一的消息传递模型&#xff0c;其中每个消息只能被一个接收者消费。发送者将消息发送到队列中&#xff0c;而接收者从队列中获取消息并进行处理&#xff0c;…...

python判断语句

1.布尔类型 进行判断&#xff0c;只有是(True&#xff1a;本质上是一个数字&#xff0c;记作1)和否(False&#xff1a;本质上是一个数字&#xff0c;记作0)。 定义变量存储布尔类型数据: 变量名称 布尔类型字面量 a True代码演示&#xff1a; a True print(type(a))输出结…...

C# 虚方法

在C#中&#xff0c;虚方法&#xff08;virtual methods&#xff09;是一种允许派生类&#xff08;子类&#xff09;覆盖&#xff08;重写&#xff09;基类&#xff08;父类&#xff09;中的方法的技术。虚方法的定义和使用如下&#xff1a; 基类中定义虚方法&#xff1a; pub…...

微信小程序,动态设置三级联动, 省市区街道

1.第一步 传parentId0 查询省份 2.第二步 选择省份,传pathId选择省份的pathId, 不传parentId,会查询出 市/县数据 3.第三步 根据选择县的parentId 查询街道数据,传parentId选择的县id 4.选择结果回显 显示所选择的 path 以/分割 取最后一级<van-dropdown-menu…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...