华为机试 - 最大化控制资源成本

news2024/11/15 4:40:34

目录

题目描述

输入描述

输出描述

用例

题目解析

算法源码


题目描述

公司创新实验室正在研究如何最小化资源成本,最大化资源利用率,请你设计算法帮他们解决一个任务混部问题:

有taskNum项任务,每个任务有开始时间(startTime),结束时间(endTime),并行度(parallelism)三个属性,

并行度是指这个任务运行时将会占用的服务器数量,一个服务器在每个时刻可以被任意任务使用但最多被一个任务占用,任务运行完成立即释放(结束时刻不占用)。

任务混部问题是指给定一批任务,让这批任务由同一批服务器承载运行,

请你计算完成这批任务混部最少需要多少服务器,从而最大化控制资源成本。

输入描述

第一行输入为taskNum,表示有taskNum项任务
接下来taskNum行,每行三个整数,表示每个任务的

开始时间(startTime ),结束时间(endTime ),并行度(parallelism)

输出描述

一个整数,表示最少需要的服务器数量

备注

  • 1 <= taskNum <= 100000
  • 0 <= startTime < endTime <= 50000
  • 1 <= parallelism <= 100

用例

输入3
2 3 1
6 9 2
0 5 1
输出2
说明

一共有三个任务,

第一个任务在时间区间[2, 3]运行,占用1个服务器,
第二个任务在时间区间[6, 9]运行,占用2个服务器,
第三个任务在时间区间[0, 5]运行,占用1个服务器,
需要最多服务器的时间区间为[2, 3]和[6, 9],需要2个服务器。

输入2
3 9 2
4 7 3
输出5
说明

一共两个任务,

第一个任务在时间区间[3, 9]运行,占用2个服务器,
第二个任务在时间区间[4, 7]运行,占用3个服务器,
需要最多服务器的时间区间为[4, 7],需要5个服务器。

题目解析

用例1图示如下:

用例2图示如下:

通过上面两个图示,我们可以看出,交集重叠越多的时间段内所需的服务器数越大,即题目所要求的最少服务器数。

我的解题思路如下:

先将任务按照开始时间升序排序,比如用例1,就得到了任务顺序如下:

[ [0,5,1], [2,3,1], [6,9,2] ]

然后,将每个任务的时间段的开始时间点和结束时间点都提取出来放到一个set集合中,即得到

[0,5,2,3,6,9]

然后将集合转为数组,进行升序排序

[0,2,3,5,6,9]

现在我得到了一个升序的关键时间点数组[0,2,3,5,6,9],以及一个开始时间升序的任务数组[ [0,5,1], [2,3,1], [6,9,2] ]。

现在,建立一个双重for,外层遍历关键时间点数组,每遍历到一个关键时间点kp,就去和每一个任务数组的时间区间比较,看kp在不在对应任务的时间区间(左闭右开,即区间不包含结束时间),如果在,则该时间点的服务器数量 += 该任务所需的服务器数量。

代码如下:

function getResult(arr) {
  // 任务数组按照任务开始时间升序排序
  arr.sort((a, b) => a[0] - b[0]);

  // 将所有的关键时间点存入keyPoints集合中
  let keyPoints = new Set();
  for (let [s, e] of arr) {
    keyPoints.add(s);
    keyPoints.add(e);
  }
    
  // 关键时间点升序排序
  keyPoints = [...keyPoints].sort((a,b) => a-b);

  let max = 0;
  
  // 遍历每一个关键时间点
  for (let kp of keyPoints) {
    let sum = 0;
    
    for (let i = 0; i < arr.length; i++) {
      const [s, e, c] = arr[i];

      // 如果关键时间点在任务的时间区间内,则该关键时间点所需服务器数量 += 当前任务服务器数量
      if (kp >= s && kp < e) sum += c;
    }

    max = Math.max(max, sum);
  }

  return max;
}

但是上面这个时间复杂度是O(n*m),n就是startTime~endTime,m就是taskNum

  • 1 <= taskNum <= 100000
  • 0 <= startTime < endTime <= 50000

因此,差不多五十亿次循环,那肯定超时,因此我们需要对算法进行优化。

优化点1:

提前结束内层循环

比如上面例子中,关键时间点0,在和2~3时间段区间比较时,可以发现 0 < 2,因此我们其实可以在此时终止内层循环,因为内层循环是对任务的循环,而任务已经按照开始时间升序了,因此如果 0 不可能出现在2~3区间中,那么0 肯定也不会出现在后面的任务的时间区间中,比如6~9。

优化点2:

排除非必要检查区间

内层循环,每次都是从第0个任务开始,如上图,关键时间点6, 对于0~5区间和2~3区间来说,6>5,6>3,因此 关键时间点6 不可能出现在0~5区间和2~3区间中,而关键时间点数组keyPoints已经按照升序排序了,因此6后面的关键时间点必然也不可能出现在这两个区间中。

因此,我们可以定义一个ignore集合,将0~5区间和2~3区间对应的内层循环的索引 i 缓存起来,这样6后面的关键时间点,在比较前,先看看 当前内层索引 i 在不在 ignore集合中,若在则跳过。

有人肯定会有疑问,为什么不直接将内层循环的起始位置提前到 6~9 区间所在索引位置呢?

比如关键时间点6,发现前两个区间都不会和自己有交集,因此下次内层循环,就从i=3开始循环,即从6~9区间开始循环,这样关键时间点9,就可以避免再次和0~5, 2~3比较了。

我们可以看下面例子

3
2 3 1
6 9 2
0 10 1

我们再看关键时间6,虽然不再2~3区间,但是还在0~10区间,因此我们不能粗暴地提前内层循环起始索引,只能用ignore集合来保存需要忽略任务对应索引 

算法源码

/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

const lines = [];
let n;
rl.on("line", (line) => {
  lines.push(line);

  if (lines.length === 1) {
    n = lines[0] - 0;
  }

  if (n && lines.length === n + 1) {
    const arr = lines.slice(1).map((line) => line.split(" ").map(Number));

    console.log(getResult(arr));

    lines.length = 0;
  }
});

function getResult(arr) {
  arr.sort((a, b) => a[0] - b[0]);

  let keyPoints = new Set();
  for (let [s, e] of arr) {
    keyPoints.add(s);
    keyPoints.add(e);
  }

  keyPoints = [...keyPoints].sort((a,b) => a-b);

  let max = 0;
  const ignore = new Set()
  
  for (let kp of keyPoints) {
    let sum = 0;
    for (let i = 0; i < arr.length; i++) {
      if(ignore.has(i)) continue// 优化

      const [s, e, c] = arr[i];

      if (kp < s) break; // 优化
      else if (kp < e) sum += c;
      else ignore.add(i)// 优化
    }

    max = Math.max(max, sum);
  }

  return max;
}

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

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

相关文章

数字图像处理实验(一)|图像的基本操作和基本统计指标计算

文章目录一、实验目的二、实验主要仪器设备三、实验原理(1)将一幅图像视为一个二维矩阵。(2)利用MATLAB图像处理工具箱读、写和显示图像文件。(3)计算图像的有关统计参数。(4)改变图像尺寸、旋转图像、裁剪图像四、实验内容(1)用imwrite写入图像(2) 用imread读入一幅图像(自选)…

opencv c++ 图像形态学操作

1、图像的形态学操作 包括图像的腐蚀、膨胀、开、闭、形态学梯度、顶帽、黑帽、分支主题、结构元素等操作。 具体概念参考&#xff1a;(41条消息) 图像处理-形态学处理_Gooddz的博客-CSDN博客_图像处理 形态学 1.1、膨胀 用33的核去扫描二值图像&#xff0c;当核与图像中的前景…

[附源码]JAVA毕业设计仟侬堂茶具网站(系统+LW)

[附源码]JAVA毕业设计仟侬堂茶具网站&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&a…

LeetCode中等题之查找和替换模式

题目 你有一个单词列表 words 和一个模式 pattern&#xff0c;你想知道 words 中的哪些单词与模式匹配。 如果存在字母的排列 p &#xff0c;使得将模式中的每个字母 x 替换为 p(x) 之后&#xff0c;我们就得到了所需的单词&#xff0c;那么单词与模式是匹配的。 &#xff0…

Git(第二篇)——Git的常见操作

Git&#xff08;第二篇&#xff09;——Git的常见操作 目录Git&#xff08;第二篇&#xff09;——Git的常见操作一、Git版本控制介绍组成结构图命令速查常用命令二、下载并安装GIT设置字体查询git三、码云上的操作码云配置环境注册账号登录码云创建仓库创建远程仓库(在码云官网…

通讯录管理系统

目录 1.系统需求 2.创建项目 3.菜单功能 4.退出功能 5.添加联系人 5.1设计联系人结构体、设计通讯录结构体 5.2main函数中创建通讯录 5.3封装添加联系人函数 5.4测试添加联系人 6.显示联系人 7.删除联系人 7.1封装检测联系人是否存在 7.2删除联系人&#xff0c;测试删除联…

当我们的执行 java -jar xxx.jar 的时候底层到底做了什么?

大家都知道我们常用的 SpringBoot 项目最终在线上运行的时候都是通过启动 java -jar xxx.jar 命令来运行的。 那你有没有想过一个问题&#xff0c;那就是当我们执行 java -jar 命令后&#xff0c;到底底层做了什么就启动了我们的 SpringBoot 应用呢&#xff1f; 或者说一个 S…

Redux使用详解(一) Redux的核心思想与基本使用

Redux 理解javascript纯函数 函数式编程中有一个非常重要的概念叫纯函数&#xff0c;JavaScript符合函数式编程的范式&#xff0c;所以也有纯函数的概念&#xff1b; 在react开发中纯函数是被多次提及的&#xff1b; 比如react中组件就被要求像是一个纯函数&#xff08;为什么…

使用STM32F103C8T自制freejoy控制板

1. 软件准备 1.1 STM公司的官方工具&#xff1a; STM32 ST-LINK Utility 已经更名为 STM32CubeProgrammer STSW-LINK004 - STM32 ST-LINK utility (replaced by STM32CubeProgrammer) - STMicroelectronics 1.2 FreeJoyConfiguratorQt V1.7.1 这个是刷好固件后的配置、调…

D-025 DP硬件电路设计

DP硬件电路设计1 简介1.1 DP接口分类1.2 DP接口和HDMI接口的区别1.3 DP接口的优势2 硬件层3 接口定义4 原理图设计1 简介 Display是一种新型的标准化的数字式视频接口标准&#xff0c;其支持的功能与HDMI相似&#xff0c;但是其目标是作为HDMI的补充&#xff0c;而非取代。DP …

红队渗透靶场之SickOs1.1

靶场考察知识 shellshock漏洞 shellshock即unix系统下的bash shell的一个漏洞, Bash 4.3以及之前的版本在处理某些构造的环境变量时存在安全漏洞, 向环境变量值内的函数定义后添加多余的字符串会触发此漏洞, 攻击者可利用此漏洞改变或绕过环境限制&#xff0c;以执行任意的sh…

Notepad++ ,json 、xml 格式化插件安装不了 和 github 网站访问不了 最佳解决方案

文章目录1.背景&#xff1a;2. 解决方法&#xff1a;方法一&#xff1a;修改hosts方法二&#xff1a; 通过 Watt Toolkit 加速1.简介&#xff1a;2.安装步骤&#xff1a;1.背景&#xff1a; 最近notpad 安装 JSON 和 xml 格式化工具安装不上&#xff0c;发现插件的地址 github…

docker之数据卷(Data Volumes)dockerfile

这里写目录标题宿主机与容器之间的文件拷贝数据卷数据卷容器Dockerfile自定义centos&#xff0c;具备vim及ifconfig作用&#xff08;体会学习Dockerfile的意义&#xff09;自定义tomcat8&#xff08;熟悉几乎所有的Dockerfile命令&#xff09;宿主机与容器之间的文件拷贝 引言…

故障分析 | Greenplum 集群 standby 故障处理

作者&#xff1a;杨文 DBA&#xff0c;负责客户项目的需求与维护&#xff0c;没有擅长&#xff0c;会点数据库&#xff0c;不限于MySQL、Redis、Cassandra、GreenPlum、ClickHouse、Elastic、TDSQL等等。 本文来源&#xff1a;原创投稿 *爱可生开源社区出品&#xff0c;原创内容…

SM4分组密码算法

对称加密算法SM4SM4算法介绍一、SM4加密流程二、轮函数F1.合成置换T3.非线性变换τ2.线性变换L4.加密的结果总结SM4算法介绍 SM4.0于2013年3月被列为国家密码行业标准“GM/T 0002-2012《SM4分组密码算法》&#xff08;原SMS4分组密码算法&#xff09;”。2016年被列入国家标准…

blender assetBrowser 资产浏览器

文章目录简介.基础操作打开资产浏览器.标记资产.资产库位置设置与加载其他工程的资产库.为资产设置分类.设置资产的属性.根据类型筛选资产.标记材质为资产.标记天空盒材质为资产.标记动作为资产.简介. 1 类似于unity的预制体&#xff0c;可以直接从资产浏览器里拖出来 2 创建时…

什么是缓存架构,什么是后端分布式多级缓存架构,全文解析带你了解其中门道

文章目录浏览器缓存客户端缓存CDN缓存反向代理缓存本地缓存分布式缓存其他&#xff1a;缓存命中率缓存问题&#xff1a;缓存穿透缓存问题&#xff1a;缓存击穿缓存问题&#xff1a;缓存雪崩缓存问题&#xff1a;缓存一致性缓存的其他问题开篇01数据库缓存1.1.MySQL查询缓存1.2.…

CAS登录认证

CAS最基本的协议过程&#xff1a; 名词解释 Ticket Grangting Ticket(TGT) &#xff1a; TGT是CAS为用户签发的登录票据&#xff0c;拥有了TGT&#xff0c;用户就可以证明自己在CAS成功登录过。TGT封装了Cookie值以及此Cookie值对应的用户信息。用户在CAS认证成功后&#xff0c…

应用于供暖、供水管道等场景的一种智能控制阀

智能控制阀&#xff0c;顾名思义就是能够实现智能化控制功能的一种控制阀。它有什么用处呢&#xff1f; TSM-04V无线智能控制阀由锂亚电池供电、超长续航&#xff0c;具有无线远程配置功能&#xff0c;是一种高可靠性阀控设备。自带断码显示屏&#xff0c;可以查看设备的电量、…

在VScode中使用Jupyter Notebook的一些技巧

目录 一、VScode中Jupyter Notebook的优点 二、Cell命令模式目前支持的Jupyter Notebook快捷 三、Cell编辑模式下支持的Vscode快捷键&#xff08;只描述与编辑相关的那些快捷键&#xff09;​​​​​​​ 一、VScode中Jupyter Notebook的优点 1.写py代码和使用Notebook经常…