LFU缓存(Leetcode460)

例题:

分析:

这道题可以用两个哈希表来实现,一个hash表(kvMap)用来存储节点,另一个hash表(freqMap)用来存储双向链表,链表的头节点代表最近使用的元素,离头节点越远的节点代表最近最少使用的节点。

注意:freqMap 的 key 为节点的使用频次。

下图是freqMap的结构:

这是kvMap: 它的key没有什么特殊含义,value是储存的节点

题目中调用get方法会增加元素的使用次数(freq),这时在freqMap中需要将该节点转移到对应的位置上(比如该节点使用了两次,那就把该节点转移到key为2的位置上去)

put方法分为两种情况:如果要添加的key不存在,说明是新元素,放到key为1的位置上,如果key存在,此时是修改操作,改变元素的value值,对应的频次+1,同样放到对应的位置上。

淘汰策略:要保证两个hash表中的节点数一致。

代码实现:
package leetcode;

import java.util.HashMap;

//设计LFU缓存
public class LFUCacheLeetcode460 {

    static class LFUCache {

        static class Node{
            Node prev;
            Node next;
            int key;
            int value;
            int freq = 1;
            public Node(){

            }
            public Node(int key, int value) {
                this.key = key;
                this.value = value;
            }
        }

        static class DoublyLinkedList{
            Node head;
            Node tail;
            int size;

            public DoublyLinkedList(){
                head = tail = new Node();
                head.next = tail;
                tail.prev = head;
            }

            //头部添加   head<->1<->2<->tail  添加3
            public void addFirst(Node node){
                Node oldFirst = head.next;
                oldFirst.prev = node;
                head.next = node;
                node.prev = head;
                node.next = oldFirst;
                size++;
            }

            //指定节点删除   head<->1<->2<->3<->tail  删除2
            public void remove(Node node){
                Node prev = node.prev;
                Node next = node.next;
                prev.next = next;
                next.prev = prev;
                size--;
            }

            //删除最后一个节点
            public Node removeLast(){
                Node last = tail.prev;
                remove(last);
                return last;
            }

            //判断双向链表是否为空
            public boolean isEmpty(){
                return size == 0;
            }
        }

        private HashMap<Integer,Node> kvMap = new HashMap<>();
        private HashMap<Integer,DoublyLinkedList> freqMap = new HashMap<>();
        private int capacity;
        private int minFreq = 1;
        public LFUCache(int capacity) {
            this.capacity = capacity;
        }

        /*
        * 获取节点  不存在:返回 -1
        *           存在: 增加节点的使用频次,将其转移到频次+1的链表中
        *           判断旧节点所在的链表是否为空,更新最小频次minFreq
        * */
        public int get(int key) {
            if(!kvMap.containsKey(key)){
                return -1;
            }
            Node node = kvMap.get(key);
            //先删除旧节点
            DoublyLinkedList list = freqMap.get(node.freq);
            list.remove(node);
            //判断当前链表是否为空,为空可能需要更新最小频次
            if(list.isEmpty() && node.freq == minFreq){
                minFreq++;
            }
            node.freq++;
            //将新节点放入新位置,可能该频次对应的链表不存在,不存在需要创建
            freqMap.computeIfAbsent(node.freq, k -> new DoublyLinkedList())
                    .addFirst(node);
            return node.value;
        }

        /*
        * 更新
        *     将节点的value更新,增加节点的使用频次,将其转移到频次+1的链表中
        * 新增
        *     检查是否超过容量,若超过,淘汰minFreq链表的最后节点
        *     创建新节点,放入kvMap,并加入频次为 1 的双向链表
        * */
        public void put(int key, int value) {
            if(kvMap.containsKey(key)){ //更新
                Node node = kvMap.get(key);
                DoublyLinkedList list = freqMap.get(node.freq);
                list.remove(node);
                if(list.isEmpty() && node.freq == minFreq){
                    minFreq++;
                }
                node.freq++;
                freqMap.computeIfAbsent(node.freq, k -> new DoublyLinkedList())
                        .addFirst(node);
                node.value = value;
            }else{ //新增
                //先判断容量是否已满
                if(kvMap.size() == capacity){
                    //执行淘汰策略
                    Node node = freqMap.get(minFreq).removeLast();
                    kvMap.remove(node.key);
                }
                Node node = new Node(key, value);
                kvMap.put(key, node);
                //加入频次为1的双向链表
                freqMap.computeIfAbsent(1, k -> new DoublyLinkedList())
                        .addFirst(node);
                minFreq = 1;
            }
        }
    }

    public static void main(String[] args) {
        LFUCache cache = new LFUCache(2);
        cache.put(1, 1);
        cache.put(2, 2);
        System.out.println(cache.get(1)); // 1 freq=2
        cache.put(3, 3);
        System.out.println(cache.get(2)); // -1
        System.out.println(cache.get(3)); // 3 freq=2
        cache.put(4, 4);
        System.out.println(cache.get(1)); // -1
        System.out.println(cache.get(3)); // 3  freq=3
        System.out.println(cache.get(4)); // 4  freq=2

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/372536.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

APN设置流程分析

源码流程分析 前期概要 此流程分析是在不同平台可能不一致,只能作为参考文档,是属于一个通用流程文档。 源码分析 入口 首先是界面,我在此平台的界面如下: 对应的入口源码位置在Settings的ApnSettings中

CAN通信----(创芯科技)CAN分析仪----转CANTest使用

点击进入官方链接进行下载创芯科技 CAN分析仪资料包&#xff1a; 创芯科技的官网&#xff1a;https://m.zhcxgd.com/ 我使用的是至尊版红色带OBD转接头的&#xff1a; 所有下图是我选择…

企业网络采用SD-WAN的优势

近年来&#xff0c;SD-WAN成为企业网络领域的一项热门技术&#xff0c;为传统网络带来了新的变革。SD-WAN&#xff08;Software Defined Wide Area Network&#xff0c;软件定义广域网&#xff09;以其灵活性、可管理性和低成本而备受青睐。它不仅能够创建成熟的专用网络&#…

对多面体数据进行裁剪和加盖的功能

开发环境&#xff1a; Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example demo解决问题&#xff1a;对多面体数据进行裁剪和加盖的功能。 关键点&#xff1a; 创建了一个平面&#xff0c;并将其定位在输入多面体数据的中心位置&#xff…

Transformer实战-系列教程7:SwinTransformer 算法原理 1

&#x1f6a9;&#x1f6a9;&#x1f6a9;Transformer实战-系列教程总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 1、SwinTransformer SwinTransformer 可以看作为一个backbone用来做分类、检测、分割都是非常好…

目标检测:3采用YOLOv8 API训练自己的模型

​ 目录 ​1.YOLOv8 的新特性 2.如何使用 YOLOv8? 3使用YOLOv8训练模型 4.验证训练集 5.测试训练集 6.测验其他图片 7 其他问题 参考: 1.YOLOv8 的新特性 Ultralytics 为 YOLO 模型发布了一个全新的存储库。它被构建为 用于训练对象检测、实例分割和图像分类模型的统…

什么是Vue样式穿透以及常用的实现方法

在Web前端开发中&#xff0c;样式穿透是一个重要的主题&#xff0c;它可以帮助我们更好地定制化组件样式&#xff0c;提升用户体验。本文将为您介绍Vue中样式穿透的概念&#xff0c;以及几种常用的实现方法&#xff0c;希望对您的前端开发工作有所帮助。 什么是样式穿透&#…

Java on Azure Tooling 2024年1月更新|Azure Key Vault 支持、示例项目创建支持及更多

作者&#xff1a;Jialuo Gan - Program Manager, Developer Division At Microsoft 排版&#xff1a;Alan Wang 大家好&#xff0c;欢迎来到 2024 年 Java on Azure 工具的首次更新。在本次更新中&#xff0c;我们将介绍对于 Azure Key Vault 支持、基于 Azure 示例项目的创建支…

JavaWeb之HTML-CSS --黑马笔记

什么是HTML ? 标记语言&#xff1a;由标签构成的语言。 注意&#xff1a;HTML标签都是预定义好的&#xff0c;HTML代码直接在浏览器中运行&#xff0c;HTML标签由浏览器解析。 什么是CSS ? 开发工具 VS Code --安装文档和安装包都在网盘中 链接&#xff1a;https://p…

服务器性能监控管理方法及工具

服务器是组织数据中心的主干&#xff0c;无论是优化的用户体验&#xff0c;还是管理良好的资源&#xff0c;服务器都能为您完成所有工作&#xff0c;保持服务器随时可用和可访问对于面向业务的应用程序和服务以最佳水平运行至关重要。 理想的服务器性能需要主动监控物理和虚拟…

Jvm FullGC 如何排查?

使用场景 我们在使用系统时&#xff0c;有时请求和响应会变得特别慢&#xff0c;系统也变得很卡。 有可能是FullGC的问题&#xff0c;可以逐步地进行排查。 使用jps和top确定进程号pid jps可以列出正在运行的jvm进程&#xff0c;并显示jvm执行主类名称( main()函数所在的类…

第5课 使用FFmpeg将rtmp流再转推到rtmp服务器

本课对应源文件下载链接&#xff1a; https://download.csdn.net/download/XiBuQiuChong/88801992 通过前面的学习&#xff0c;我们已经可以正常播放网络rtmp流及本地mp4文件。这节课&#xff0c;我们将在前面的基础上实现一个常用的转推功能&#xff1a;读取rtmp流或mp4文件并…

移动云ONAIR媒体云全解读!媒体内容数字化融合一站式解决方案

当下&#xff0c;传统媒体面临着诸多挑战&#xff0c;如何利用信息技术提升内容的质量、形式和分发效率&#xff0c;成为媒体行业的迫切需求。移动云作为数字中国建设的“主力军”&#xff0c; 立足于新兴媒体与云计算市场的变化与需求&#xff0c;推出了ONAIR 媒体云解决方案&…

计算机设计大赛 深度学习+opencv+python实现车道线检测 - 自动驾驶

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV56 数据集处理7 模型训练8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &am…

C++之强制转换

目录 static_cast const_cast 思维导图 类型转换有c风格的&#xff0c;当然还有c风格的。c风格的转换的格式很简单 TYPE a &#xff08;TYPE&#xff09;EXPRESSION; 但是c风格的类型转换有不少的缺点&#xff0c;有的时候用c风格的转换是不合适的&#xff0c;因为它可以在…

【复现】智慧园区综合管理平台文件上传漏洞_40

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 智慧园区管理平台基于GISBIM的云平台数据中心和物联网技术为核心&#xff0c;将各项基础设施连接成一个有机的整体&#xff0c;通…

Vector CANdb++ Editor和CANdb++ Admin的区别

目录 1 CANdb Editor和CANdb Admin的功能偏差 2 CANdb Program窗口 3 下载并安装CANdb Editor和CANdb Admin 3.1 安装CANdb Admin.J1939 3.0 SP27 优质博文推荐阅读&#xff08;单击下方链接&#xff0c;即可跳转&#xff09;&#xff1a; Vector工具链 CAN Matrix DBC …

[Vue3]父子组件相互传值数据同步

简介 vue3中使用setup语法糖&#xff0c;父子组件之间相互传递数据及数据同步问题 文章目录 简介父传子props传递值 使用v-bind绑定props需要计算toRefcomputed emit传递方法 使用v-on绑定 子传父expose v-model总结 父传子 props传递值 使用v-bind绑定 父组件通过props给子…

代码生成器(新):mybatis-plus-generator使用指南

代码生成器&#xff08;新&#xff09;官网 后端代码&#xff1a;点击查看 LearnElementUiAndSpringBoot 提醒&#xff1a;LearnElementUiAndSpringBoot下载完后&#xff0c;在运行调试 Main.java里的main方法之前&#xff0c;除了utils包和Main.java文件&#xff0c;其他包需…

机器学习逻辑回归模型训练与超参数调优 ##3

文章目录 [TOC]基于Kaggle电信用户流失案例数据&#xff08;可在官网进行下载&#xff09;逻辑回归模型训练逻辑回归的超参数调优 基于Kaggle电信用户流失案例数据&#xff08;可在官网进行下载&#xff09; 数据预处理部分可见&#xff1a; 机器学习数据预处理方法&#xff0…