华为OD机试 - 文件缓存系统 - 双向链表(Java 2024 D卷 100分)

news2024/11/24 2:10:55

在这里插入图片描述

华为OD机试 2024D卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试(JAVA)真题(D卷+C卷+A卷+B卷)》。

刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

请设计一个文件缓存系统,该文件缓存系统可以指定缓存的最大值(单位为字节)。文件缓存系统有两种操作:存储文件(put)和读取文件(get)

操作命令为put fileName fileSize或者get fileName

存储文件是把文件放入文件缓存系统中;读取文件是从文件缓存系统中访问已存在的文件,如果文件不存在,则不作任何操作。

当缓存空间不足以存放新的文件时,根据规则删除文件,直到剩余空间满足新的文件大小为止,再存放新文件。

具体的删除规则为:文件访问过后,会更新文件的最近访问时间和总的访问次数,当缓存不够时,按照第一优先顺序为访问次数从少到多,第二顺序为时间从老到新的方式来删除文件。

二、输入描述

第一行为缓存最大值m(整数,取值范围为0 < m <= 52428800)

第二行为文件操作序列个数n(0 <= n <= 300000)

从第三行起为文件操作序列,每个序列单独一行

文件操作定义为"op fileName fileSize"

fileName是文件名,fileSize是文件大小

三、输出描述

输出当前文件缓存中的文件名列表,文件名用英文逗号分隔,按字典顺序排序

如:a,c

如果文件缓存中没有文件,则输出NONE

补充说明

  1. 如果新文件的文件名和文件缓存中已有的文件名相同,则不会放在缓存中
  2. 新的文件第一次存入到文件缓存中时,文件的总访问次数不会变化,文件的最近访问时间会更新到最新时间
  3. 每次文件访问后,总访问次数加1,最近访问时间更新到最新时间
  4. 任何两个文件的最近访问时间不会重复
  5. 文件名不会为空,均为小写字母,最大长度为10
  6. 缓存空间不足时,不能存放新文件
  7. 每个文件大小都是大于0的整数

1、输入

50
6
put a 10
put b 20
get a
get a
get b
put c 30

2、输出

a,c

四、解题思路

本题要求实现一个文件缓存系统,支持存储文件 (put) 和读取文件 (get) 操作。缓存的容量是有限的,当缓存空间不足时需要根据一定的规则删除文件。具体的删除规则为:

  1. 优先删除访问次数最少的文件。
  2. 如果访问次数相同,优先删除最近最少访问的文件。

为了解决这个问题,我们可以使用两个数据结构:

  1. HashMap:用于快速存取文件的节点信息。
  2. 双向链表:用于管理文件的访问顺序和频次。

具体步骤如下:

  1. 数据结构设计:
    • Node 类:表示文件的节点,包含文件名、文件大小、访问次数、前后节点的引用。
    • DoublyLinkedList 类:双向链表,用于管理文件节点,支持在链表尾部添加节点和删除指定节点。
    • LFUCache 类:文件缓存系统,包含一个 keyMap(存储文件名与节点的映射)和一个 freqMap(存储访问次数与链表的映射)。
  2. 操作实现:
    • put 方法:存储文件。如果缓存空间不足,则根据规则删除文件后再存储新文件。
    • get 方法:读取文件并更新其访问次数。
    • incNodeFreq 方法:更新节点的访问次数,并移动节点到新的频次链表。
  3. 具体步骤:
    • 初始化:读取缓存最大容量和操作序列数量,创建 LFUCache 对象。
    • 处理操作序列:逐条处理 put 和 get 操作,更新缓存。
    • 输出结果:输出缓存中的文件名列表,按字典顺序排序。如果缓存为空,输出 “NONE”。

五、Java算法源码

public class Test01 {
    // 定义双向链表节点
    static class Node {
        String fileName; // 文件名
        int fileSize; // 文件大小
        int accessCount; // 访问次数
        Node prev; // 前一个节点
        Node next; // 后一个节点

        public Node(String fileName, int fileSize, int accessCount) {
            this.fileName = fileName;
            this.fileSize = fileSize;
            this.accessCount = accessCount;
            this.prev = null;
            this.next = null;
        }
    }

    // 定义双向链表
    static class DoublyLinkedList {
        int size; // 链表节点数
        Node head; // 链表头节点
        Node tail; // 链表尾节点

        // 在链表尾部添加节点
        public void addLast(Node node) {
            if (this.size == 0) {
                this.head = node;
                this.tail = node;
            } else {
                this.tail.next = node;
                node.prev = this.tail;
                this.tail = node;
            }
            this.size++;
        }

        // 删除指定节点
        public void remove(Node node) {
            if (this.size == 0) return;

            if (this.size == 1) {
                this.head = null;
                this.tail = null;
            } else if (node == this.head) {
                this.head = this.head.next;
                this.head.prev = null;
            } else if (node == this.tail) {
                this.tail = this.tail.prev;
                this.tail.next = null;
            } else {
                node.prev.next = node.next;
                node.next.prev = node.prev;
            }
            this.size--;
        }
    }

    static class LFUCache {
        HashMap<String, Node> keyMap; // 存储文件名与节点的映射
        HashMap<Integer, DoublyLinkedList> freqMap; // 存储访问次数与链表的映射
        int capacity; // 文件系统总容量
        int minFreq; // 最少访问次数

        public LFUCache(int capacity) {
            this.capacity = capacity;
            this.minFreq = 0;
            this.keyMap = new HashMap<>();
            this.freqMap = new HashMap<>();
        }

        // 获取文件并更新其访问次数
        public void get(String fileName) {
            if (!this.keyMap.containsKey(fileName)) return;

            Node node = this.keyMap.get(fileName);
            incNodeFreq(node); // 更新访问次数
        }

        // 存储文件
        public void put(String fileName, int fileSize) {
            if (this.keyMap.containsKey(fileName)) return;

            while (this.capacity < fileSize) {
                if (this.minFreq == 0) return;

                DoublyLinkedList minFreqList = this.freqMap.get(this.minFreq);
                Node removeNode = minFreqList.head;
                this.capacity += removeNode.fileSize;
                minFreqList.remove(removeNode);
                this.keyMap.remove(removeNode.fileName);

                if (minFreqList.size == 0) {
                    this.freqMap.remove(this.minFreq);
                    if (this.freqMap.size() > 0) {
                        this.minFreq = this.freqMap.keySet().stream().min((a, b) -> a - b).get();
                    } else {
                        this.minFreq = 0;
                    }
                }
            }

            this.capacity -= fileSize;
            this.minFreq = 1;
            Node node = new Node(fileName, fileSize, this.minFreq);
            this.freqMap.putIfAbsent(this.minFreq, new DoublyLinkedList());
            this.freqMap.get(this.minFreq).addLast(node);
            this.keyMap.put(fileName, node);
        }

        // 更新节点的访问次数
        public void incNodeFreq(Node node) {
            DoublyLinkedList list = this.freqMap.get(node.accessCount);
            list.remove(node);
            if (list.size == 0) {
                this.freqMap.remove(node.accessCount);
                if (node.accessCount == this.minFreq) {
                    this.minFreq++;
                }
            }

            node.accessCount++;
            this.freqMap.putIfAbsent(node.accessCount, new DoublyLinkedList());
            this.freqMap.get(node.accessCount).addLast(node);
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 读取缓存最大容量
        int maxCapacity = Integer.parseInt(scanner.nextLine());
        LFUCache lfuCache = new LFUCache(maxCapacity);

        // 读取操作序列的数量
        int operationCount = Integer.parseInt(scanner.nextLine());
        for (int i = 0; i < operationCount; i++) {
            String[] operation = scanner.nextLine().split(" ");

            String op = operation[0];
            String fileName = operation[1];

            if ("put".equals(op)) {
                int fileSize = Integer.parseInt(operation[2]);
                lfuCache.put(fileName, fileSize);
            } else {
                lfuCache.get(fileName);
            }
        }

        // 输出结果
        if (lfuCache.capacity == maxCapacity) {
            System.out.println("NONE");
        } else {
            StringJoiner sj = new StringJoiner(",");
            lfuCache.keyMap.keySet().stream().sorted().forEach(sj::add);
            System.out.println(sj);
        }
    }
}

六、效果展示

1、输入

50
7
put a 10
put b 20
get a
get a
get b
get b
put c 30

2、输出

b,c

3、说明

在这里插入图片描述


🏆下一篇:华为OD机试 - 简易内存池 - 逻辑分析(Java 2024 C卷 200分)

🏆本文收录于,华为OD机试(JAVA)真题(D卷+C卷+A卷+B卷)

刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自动生成列表,颜色随机 ,定时执行函数,10秒停止执行函数,按钮执行函数

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>颜色列表Color List</title><style>…

介绍并改造一个作用于Anki笔记浏览器的插件

在Anki的笔记浏览器窗口中&#xff0c;作为主体部分的表格在对获取到的笔记进行排序时&#xff0c;最多只能有一个排序字段&#xff0c;在设定笔记的排序字段后&#xff0c;没法将表格中的笔记按其他字段进行排序。要满足这个需求&#xff0c;可以使用Advanced Browser插件&…

【ai】初识pytorch

初识PyTorch 大神的例子运行: 【ai】openai-quickstart 配置pycharm工程 简单例子初识一下Pytorch 好像直接点击下载比较慢? 大神的代码 在这个例子中,首先定义一个线性模型,该模型有一个输入特征和一个输出特征。然后定义一个损失函数和一个优化器,接着生成一些简单的线性…

Spring Cloud Config配置信息自动更新原理解析

我们知道Spring Cloud Config是Spring Cloud提供的配置中心实现工具&#xff0c;我们可以通过它把配置信息存放在Git等第三方配置仓库中。每当Spring Cloud Config客户端启动时&#xff0c;就会发送HTTP请求到服务器端获取配置信息&#xff0c;这点比较好理解。但事实上&#x…

一个示例学习C语言到汇编层面

给出以下代码 #include<stdio.h> int main() {int x 0, y 0, z 0;while (1) {x 0;y 1;do {printf("%d\n", x);z x y;x y;y z;} while (x < 255);}return 0; }我们把这个程序编写成32位程序&#xff0c;然后我们放入IDA中进行分析 .text:0080187…

矩阵乘法的直觉

矩阵乘法是什么意思&#xff1f; 一种常见的观点是矩阵乘法缩放/旋转/倾斜几何平面&#xff1a; NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜…

JavaScript妙笔生花:打造沉浸式中国象棋游戏体验

前言 随着信息技术的飞速发展&#xff0c;Web开发领域也出现了翻天覆地的变化。JavaScript作为前端开发中不可或缺的编程语言&#xff0c;其重要性不言而喻。而当我们谈论到利用JavaScript打造一款沉浸式的中国象棋游戏体验时&#xff0c;我们不仅仅是在开发一个游戏&#xff0…

Web应用安全测试-权限篡改

Web应用安全测试-权限篡改 任意用户密码修改/重置 漏洞描述&#xff1a; 可通过篡改用户名或ID、暴力破解验证码等方式修改/重置任意账户的密码。 测试方法&#xff1a; 密码修改的步骤一般是先校验用户原始密码是否正确&#xff0c;再让用户输入新密码。修改密码机制绕过方式…

【Ubuntu通用压力测试】Ubuntu16.04 CPU压力测试

​ 使用 stress 对CPU进行压力测试 我也是一个ubuntu初学者&#xff0c;分享是Linux的优良美德。写的不好请大佬不要喷&#xff0c;多谢支持。 sudo apt-get update 日常先更新再安装东西不容易出错 sudo apt-get upgrade -y 继续升级一波 sudo apt-get install -y linux-to…

微信分销商城小程序源码系统在线搭建 前后端分离 带完整的安装代码包以及搭建教程

系统概述 本微信分销商城小程序源码系统采用先进的前后端分离架构设计&#xff0c;前端使用Vue.js框架开发&#xff0c;后端则基于Spring Boot构建&#xff0c;确保了系统的高可维护性、扩展性和性能。系统集商品展示、在线交易、会员管理、分销推广、订单处理、数据统计等功能…

redis存储结构

概要 首先&#xff0c;redis是一种"键值对"&#xff08;key-value&#xff09;数据库&#xff0c;也就是说&#xff0c;redis中存储的用户数据都是以key-value的方式存在的&#xff0c;而这些键值对存储于哈希表&#xff0c;这也解释了为什么redis提供的set、lpush、…

vue标签组

先看样式 再看代码 <div v-else class"relative"><n-tabs ref"tabsInstRef" v-model:value"selectValue" class"min-w-3xl myTabs"><n-tab-panev-for"(tab) in songsTags" :key"tab.name" displ…

Java集合框架源码分析:ArrayList

文章目录 一、ArrayList特性二、ArrayList底层数据结构三、ArrayList继承关系1、Serializable标记性接口2、Cloneable标记性接口3、RandomAccess标记性接口4、AbstractList抽象接口 四、ArrayList源码分析1、构造方法2、添加方法3、删除方法4、修改方法5、获取方法6、转换方法7…

数据结构(DS)C语言版:学习笔记(4):线性表

参考教材&#xff1a;数据结构C语言版&#xff08;严蔚敏&#xff0c;吴伟民编著&#xff09; 工具&#xff1a;XMind、幕布、公式编译器 正在备考&#xff0c;结合自身空闲时间&#xff0c;不定时更新&#xff0c;会在里面加入一些真题帮助理解数据结构 目录 2.1线性…

青书学堂 看视频 耍课时

1. 获取课程节点id ( /nynzy/Student/Course/GetStudyRecordAndScore ) 接口地址 2. 把所有的nodeId 保存下来 保存到 old.txt 格式 课程id 与 nodeId 用 | 隔开 3. 然后创建 test.php 注意把 cookie 换成自己的 <?php$oldFilename ./old.txt; $newFilename ./new.…

idea插件开发之在项目右键添加菜单

写在前面 本文看下如何在右键列表中增加菜单。 正戏 首先创建一个Action&#xff0c;要显示的menu选择ProjectViewPopupMenu&#xff0c;如下&#xff1a; action public class CAction extends AnAction {Overridepublic void actionPerformed(AnActionEvent e) { // …

Excel 常用技巧(四)

Microsoft Excel 是微软为 Windows、macOS、Android 和 iOS 开发的电子表格软件&#xff0c;可以用来制作电子表格、完成许多复杂的数据运算&#xff0c;进行数据的分析和预测&#xff0c;并且具有强大的制作图表的功能。由于 Excel 具有十分友好的人机界面和强大的计算功能&am…

新项目Springboot报错: Whitelabel Error Page

问题&#xff1a; 新项目Springboot报错: Whitelabel Error Page 解析&#xff1a; 一般出现这个问题的原因就是目录结构不正确&#xff0c;导致主应用程序类&#xff08;Main application class&#xff09;扫描不到controller类。 默认情况下主应用程序类&#xff08;Main …

【Git】win本地 git bash:Connect reset by 20.205.243.166 port22报错问题解决

win10 git bash 控制台 reset 22端口拒绝连接问题&#xff1a; Connection reset by 20.205.243.166 port 221、22端口 无法连接 ssh -T gitgithub.com2、尝试用443端口 仍然无法连接 ssh -T -P 443 gitgithub.com3、重写 git clone 地址 url&#xff0c;全局添加 https 前缀…

从零到一,深入浅出大语言模型的奇妙世界

2022 年底&#xff0c;OpenAI 发布的 ChatGPT 模型在全球范围内引起了巨大轰动。本文详细的介绍了大语言模型的发展历程、构建过程和大语言模型如何使用等知识&#xff0c;帮助大家搞懂大语言模型。 一、大语言模型发展历程 大模型技术并不是一蹴而就的&#xff0c;大语言模型…