学习记录:js算法(六十七):任务调度器

news2024/10/19 21:31:21

文章目录

    • 任务调度器
      • 思路一
      • 思路二

任务调度器

给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表,用字母 AZ 表示,以及一个冷却时间 n。每个周期或时间间隔允许完成一项任务。任务可以按任何顺序完成,但有一个限制:两个 相同种类 的任务之间必须有长度为 n 的冷却时间。
返回完成所有任务所需要的 最短时间间隔 。

示例 1:
输入:tasks = ["A","A","A","B","B","B"], n = 2
输出:8
解释:
在完成任务 A 之后,你必须等待两个间隔。对任务 B 来说也是一样。在第 3 个间隔,A 和 B 都不能完成,所以你需要待命。在第 4 个间隔,由于已经经过了 2 个间隔,你可以再次执行 A 任务。
 
示例 2:
输入:tasks = ["A","C","A","B","D","B"], n = 1
输出:6
解释:一种可能的序列是:A -> B -> C -> D -> A -> B。
由于冷却间隔为 1,你可以在完成另一个任务后重复执行这个任务。

示例 3:
输入:tasks = ["A","A","A","B","B","B"], n = 3
输出:10
解释:一种可能的序列为:A -> B -> idle -> idle -> A -> B -> idle -> idle -> A -> B。
只有两种任务类型,A 和 B,需要被 3 个间隔分割。这导致重复执行这些任务的间隔当中有两次待命状态。

思路一

function leastInterval(tasks, n) {
    // 初始化一个大小为26的数组,用来统计每个字母任务出现的次数。
    const taskCounts = new Array(26).fill(0);
    
    // 遍历任务列表,统计每个任务的出现次数。
    for (const task of tasks) {
        taskCounts[task.charCodeAt(0) - 'A'.charCodeAt(0)]++;
    }

    // 找出频率最高的任务的频率。
    let maxCount = Math.max(...taskCounts);
    
    // 计算频率最高任务的数量。
    let maxTaskCount = taskCounts.filter(count => count === maxCount).length;

    // 计算除了最后一个周期外,其他周期中最大频率任务的个数。
    let partCount = maxCount - 1;
    
    // 计算除了最大频率任务之外,每个周期中需要的其他任务或空闲插槽数量。
    let partLength = n - (maxTaskCount - 1);
    
    // 计算所有周期中空闲插槽的总数。
    let emptySlots = partCount * partLength;
    
    // 计算除了最大频率任务之外的所有任务的总数。
    let availableTasks = tasks.length - maxCount * maxTaskCount;
    
    // 计算实际需要的空闲插槽数量,如果emptySlots大于availableTasks,则实际需要的空闲插槽数量为emptySlots - availableTasks。
    let idles = Math.max(0, emptySlots - availableTasks);

    // 返回完成所有任务所需的最少时间,等于所有任务的执行时间加上必要空闲插槽数量。
    return tasks.length + idles;
}

讲解

  1. 统计任务频率:
    ○ 创建一个大小为 26 的数组 taskCounts,统计每个任务出现的次数。这是因为任务是由大写字母 AZ 表示的,所以数组的长度为 26
  2. 确定最高频率任务:
    ○ 通过遍历 taskCounts,找到出现次数最多的任务频率 maxCount,即任务的最高频率。
  3. 计算最高频率任务的数量:
    ○ 再次遍历 taskCounts,计算有多少个任务具有 maxCount 这样的最高频率。
  4. 计算理论上的空闲插槽数量:
    ○ 根据 maxCountn ,计算理论上在最高频率任务之间的空闲插槽数量。这是因为除了最后一个周期外,每个最高频率任务前都应该有n个空闲插槽。
  5. 计算实际需要的空闲插槽数量:
    ○ 这一步非常重要,因为实际的空闲插槽数量取决于剩余任务的数量和最高频率任务的数量。如果剩余任务不足以填满所有理论上的空闲插槽,那么实际的空闲插槽数量将少于理论值。
  6. 计算所需最少时间:
    ○ 结果是所有任务的执行时间加上必要的空闲插槽数量,确保任何两个相同任务之间至少有 n 个不同的任务。

思路二

function leastInterval(tasks, n) {
    const taskCount = Array(26).fill(0);

    // 统计每个任务的频率
    for (const task of tasks) {
        taskCount[task.charCodeAt(0) - 'A'.charCodeAt(0)]++;
    }

    const maxCount = Math.max(...taskCount);
    const maxCountTasks = taskCount.filter(count => count === maxCount).length;

    // 计算所需的时间
    const intervals = (maxCount - 1) * (n + 1) + maxCountTasks;

    // 返回最大值和任务数量的较大者
    return Math.max(intervals, tasks.length);
}

讲解

  1. 计数排序的基本思想:
    • 统计频率:创建一个数组来统计每个元素出现的次数。
    • 计算位置:根据频率数组计算每个元素在排序后数组中的位置。
    • 构建输出数组:根据位置将元素放入输出数组中。
  2. 在任务调度问题中的应用:
    • 统计每个任务的频率:维护一个数组 taskCount,其中每个索引对应一个任务(例如,A 对应 0,B 对应 1,依此类推),并统计每个任务的出现次数。
    • 找出最大频率:找到出现次数最多的任务(即最大频率)和有多少个任务具有这个最大频率。
    • 计算所需时间:
      1. 设最大频率为 maxCount,具有该频率的任务数量为 maxCountTasks。
      2. 最小时间间隔的计算公式为:intervals(maxCount−1)×(n+1)+maxCountTasks
        这里,maxCount - 1 是因为最后一个任务不需要冷却时间。
    • 返回结果:返回 intervals 和任务总数的较大者,以确保不会少于任务总数。
  3. 代码解析:
    • 任务频率统计:使用 taskCount 数组来记录每种任务的出现频率。
    • 最大频率与任务数量:使用 Math.max 找到最大频率,并通过 filter 统计有多少个任务具有该频率。
    • 计算最小时间:使用前面提到的公式计算所需的时间间隔。
    • 返回结果:返回计算出的时间和任务总数中的较大值,以确保返回的时间不小于任务总数。

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

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

相关文章

缓存框架JetCache源码解析-缓存定时刷新

作为一个缓存框架,JetCache支持多级缓存,也就是本地缓存和远程缓存,但是不管是使用着两者中的哪一个或者两者都进行使用,缓存的实时性一直都是我们需要考虑的问题,通常我们为了尽可能地保证缓存的实时性,都…

word取消自动单词首字母大写

情况说明:在word输入单词后首字母会自动变成大写 (1)点击菜单栏文件 (2)点击“更多”——>“选项” (3)点击“校对”——>“自动更正选项” (4)取消“句首字母大写…

WPF样式详解:行内样式、模板样式和页面样式的全方位分析

Windows Presentation Foundation (WPF) 是微软推出的一种用于构建桌面应用程序的UI框架。WPF 提供了强大的样式和模板机制,允许开发人员以声明的方式定义和复用UI元素的视觉外观。本文将深入探讨WPF的行内样式、模板样式和页面样式,帮助您在实际开发中更…

大数据linux操作系统

第一关:Linux的初体验 答案: cd / ls -a / (里面有空格要注意) 第二关:Linux的常用命令 答案: touch newfile mkdir newdir cp newfile newdir/newfileCpy 第三关:Linux查询命令帮助语句…

我在自动化测试方面犯过的3个大错误

每个人都会犯错误,但不管错误看起来有多糟糕,你都可以恢复过来,更重要的是,从错误中学习。 在软件开发过程的任何领域,从编码到测试,我们都会时不时地犯一些错误。通常,这些错误都很小&#xf…

Linux kernel 堆溢出利用方法

前言 本文还是用一道例题来讲解几种内核堆利用方法,内核堆利用手段比较多,可能会分三期左右写。进行内核堆利用前,可以先了解一下内核堆的基本概念,当然更好去找一些详细的内核堆的基础知识。 概述 Linux kernel 将内存分为 页…

Leetcode 字符串解码

该代码的算法思想可以分为以下几个步骤: 1. 使用栈来处理嵌套结构: 我们需要处理像 k[encoded_string] 这种格式,其中的 encoded_string 可能是嵌套的,即像 3[a2[c]] 这样的输入。因此,我们可以借助 栈(S…

音视频基础知识分享

音视频基础知识分享 RKMedia的各个组件及其交互 首先上图: 考虑到公司业务主要是相机,所以,主要去关注图像数据流,对于音频数据流直接忽略。 图像数据流向: Camera Sensor将光信号转换成电信号(Raw数据&…

【大模型】AI视频课程制作工具开发

1. 需求信息 1.1 需求背景 讲师们在制作视频的过程中,发现录制课程比较麻烦,要保证环境安静,保证录制过程不出错,很容易反复重复录制,为了解决重复录制的工作量,想通过 ai 课程制作工具,来解决…

Rust引用与C++取地址、引用的区别(C++引用、Rust解引用、C++指针)

文章目录 Rust引用与C取地址和引用的比较一、内存安全与管理Rust的内存安全机制C的内存管理 二、引用和取地址Rust的引用C的引用和取地址 三、代码示例比较修改数据的安全性Rust示例C示例 四、结论 Rust引用与C取地址和引用的比较 在程序设计语言的世界里,Rust和C都…

【C++】string类(接口使用详解 下)

我们接着【C】string类(接口使用详解 上)-CSDN博客 继续介绍string的使用。 1.string类对象的修改操作 我们就说一下用的比较多的接口。 1.1 operator 这个接口可以尾插一个字符,或者一个字符串,或者一个对象。 string s1(&qu…

Java—类和对象习题讲解

如果您觉得这篇文章对您有帮助的话 欢迎您一键三连,小编尽全力做到更好 欢迎您分享给更多人哦 目录 习题一: 习题二: 习题三:.import static 能够导入一些静态方法 习题四: 习题五: 习题六&#xff1…

[LeetCode] 415.字符串相加

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。 你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。 示例 1: 输入&#xff…

SHELL脚本之数组介绍

shell数组 一.数组介绍 一段连续的内存空间,根据需要可以存多个数据。 变量定义:从内存中申请一段空间,用来存储数据。 如果同一种类型的数据,每一个数据都定义一个变量,当机器对这些变量进行寻址的时候&#xff0…

【Neo4j】- 轻松入门图数据库

文章目录 前言-场景一、Neo4j概述二、软件安装部署1.软件下载2.软件部署3.软件使用4.语法学习 总结 前言-场景 这里用大家都了解的关系数据与图数据据库对比着说,更加方便大家理解图数据库的作用 图形数据库和关系数据库均存储信息并表示数据之间的关系。但是,关系…

Aspose.PDF功能演示:使用 JavaScript 从 PDF 中提取文本

在数据提取、业务文档自动化和文本挖掘方面,使用 JavaScript 从PDF中提取文本非常有用。它允许开发人员自动执行从 PDF 收集信息的过程,从而显著提高处理大量文档的生产力和效率。在这篇博文中,我们将学习如何使用 JavaScript 从 PDF 中提取文…

功能安全实战系列-软件FEMA分析与组件鉴定

本文框架 前言1. 功能安全分析1.1 Why1.2 What?1.3 How?1.3.1 分析范围确定1.3.2 失效模式分析1.3.3 安全措施制定1.3.4 确认是否满足功能安全目标2. 软件组件鉴定2.1 Why2.2 How?前言 在本系列笔者将结合工作中对功能安全实战部分的开发经验进一步介绍常用,包括Memory(Fl…

stable diffusion 大模型及lora等下载安装使用教程及项目目录说明

首先说明,stable diffusion大模型并非controlNet中使用的模型,这两者有根本的区别,请仔细区分。 国内可下载模型的站点: 哩布哩布 https://liblib.ai 模型分为几类,下载的时候看清楚类型,都会标记在模型…

Python编程探索:从基础语法到循环结构实践(下)

文章目录 前言🍷四、 字符串拼接:连接多个字符串🍸4.1 使用 操作符进行字符串拼接🍸4.2 使用 join() 方法进行字符串拼接🍸4.3 使用 format() 方法进行格式化拼接🍸4.4 使用 f-string(格式化字…

【Linux】进程池

目录 进程池 进程池的概念: 手搓进程池: 1、创建信道和子进程 2、通过channel控制子进程 3、回收管道和子进程 进程池 进程池的概念: 定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中…