2022-04-26:给定一个数组componets,长度为A,

componets[i] = j,代表i类型的任务需要耗时j

给定一个二维数组orders,长度为M,

orders[i][0]代表i号订单下单时间

orders[i][1]代表i号订单是哪种类型的任务,毫无疑问orders[i][1] < A

一开始所有流水线都在0时刻待命,

给定一个正数nums,表示流水线的数量,流水线编号为0 ~ nums-1

每一个流水线可以承接任何类型的任务,耗时就是componets数组给定的

所有订单的下单时间一定是有序的,也就是orders数组,是根据下单时间排序的

每一个订单开始执行的时间不能早于下单时间,

如果有多个流水线都可以执行当前订单,选择编号最小的流水线

根据上面说的任务执行细节,去依次完成所有订单

返回长度为M的数组ans,也就是和orders等长

ans[i][0]代表i号订单是由哪条流水线执行的

ans[i][1]代表i号订单的完成时间

1 <= A <= 10^5

1 <= M <= 10^5

1 <= nums <= 10^5

1 <= 时间数值 <= 10^5。

答案2022-04-26:

第一种算法大体过程:

  1. 初始化一个长度为 nums 的流水线数组 lines,初始值都为 0。

  2. 遍历订单数组 orders 中的每个订单 i,获取订单的下单时间 startTime 和任务类型 typ。

  3. 在流水线数组 lines 中查找第一个可用的流水线 usei,使得 lines[usei] <= startTime。如果找到了可用的流水线,将此订单分配给该流水线;否则,寻找结束时间最早的流水线 early,并将此订单分配给 early 流水线。

  4. 更新流水线数组 lines 中对应流水线的状态,即 lines[usei] = ans[i][1],其中 ans[i][1] 是该订单完成的时间。

  5. 将当前订单的结果保存到输出数组 ans 中,即 ans[i][0] = usei,ans[i][1] = lines[usei]。

  6. 返回 ans 数组。

时间复杂度为 O(nums * M),其中 nums 是流水线数量,M 是订单数量。空间复杂度为 O(M)。

第二种算法大体过程:

  1. 初始化一个长度为 nums 的可用流水线堆 canUseLines,以及一个睡眠流水线堆 sleepLines。

  2. 遍历订单数组 orders 中的每个订单 i,获取订单的下单时间 startTime 和任务类型 jobType。

  3. 从睡眠流水线堆 sleepLines 中弹出所有满足条件的流水线,并将这些流水线加入可用流水线堆 canUseLines 中。

  4. 从可用流水线堆 canUseLines 中选择编号最小的流水线 use,并将此订单分配给该流水线。

  5. 更新流水线的状态,即将 use 流水线从可用流水线堆 canUseLines 中弹出,更新其结束时间为此订单完成时间 ans[i][1],然后将其加入到睡眠流水线堆 sleepLines 中。

  6. 将当前订单的结果保存到输出数组 ans 中,即 ans[i][0] = use.index,ans[i][1] = use.time。

  7. 返回 ans 数组。

时间复杂度为 O(M * log(nums)),其中 M 是订单数量,nums 是流水线数量。由于使用了堆来维护可用流水线和睡眠流水线,每次操作的时间复杂度是 log(nums),因此总时间复杂度为 M * log(nums)。空间复杂度为 O(nums + M),即可用流水线堆和睡眠流水线堆的大小之和,加上输出数组 ans 的大小。

go完整代码如下:

package main

import (
"container/heap"
"fmt"
"math"
"math/rand"
"sort"
"time"
) func Times1(nums int, jobTimes []int, orders [][]int) [][]int {
lines := make([]int, nums)
n := len(orders)
ans := make([][]int, n)
for i := 0; i < n; i++ {
ans[i] = make([]int, 2)
}
for i := 0; i < n; i++ {
start, typ := orders[i][0], orders[i][1]
usei := -1
for j := 0; j < nums; j++ {
if lines[j] <= start {
usei = j
break
}
}
if usei != -1 {
ans[i][0] = usei
ans[i][1] = start + jobTimes[typ]
} else {
early := math.MaxInt32
for j := 0; j < nums; j++ {
if lines[j] < early {
early = lines[j]
usei = j
}
}
ans[i][0] = usei
ans[i][1] = early + jobTimes[typ]
}
lines[usei] = ans[i][1]
}
return ans
} type Line struct {
time int
index int
} type WakeUpHeap []*Line func (h WakeUpHeap) Len() int { return len(h) }
func (h WakeUpHeap) Less(i, j int) bool {
if h[i].time != h[j].time {
return h[i].time < h[j].time
}
return h[i].index < h[j].index
}
func (h WakeUpHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *WakeUpHeap) Push(x interface{}) {
*h = append(*h, x.(*Line))
}
func (h *WakeUpHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[:n-1]
return x
} type IndexHeap []*Line func (h IndexHeap) Len() int { return len(h) }
func (h IndexHeap) Less(i, j int) bool { return h[i].index < h[j].index }
func (h IndexHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IndexHeap) Push(x interface{}) {
*h = append(*h, x.(*Line))
}
func (h *IndexHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[:n-1]
return x
} func Times2(nums int, componets []int, orders [][]int) [][]int {
n := len(orders)
// 睡眠堆
sleepLines := make(WakeUpHeap, 0)
heap.Init(&sleepLines)
// 可用堆
canUseLines := make(IndexHeap, nums)
for i := 0; i < nums; i++ {
canUseLines[i] = &Line{0, i}
}
heap.Init(&canUseLines)
ans := make([][]int, n)
for i := 0; i < n; i++ {
ans[i] = make([]int, 2)
}
for i := 0; i < n; i++ {
startTime, jobType := orders[i][0], orders[i][1]
// 当前订单在start时刻下单,所有唤醒时间比time早的流水线全可以考虑
for len(sleepLines) > 0 && sleepLines[0].time <= startTime {
heap.Push(&canUseLines, heap.Pop(&sleepLines))
}
// 如果可以使用的流水线不存在
// 比如,2条流水线
// 第0个订单,1时刻开始,用时100万,流水线A在100万+1时刻醒来
// 第1个订单,2时刻开始,用时100万,流水线B在100万+2时刻醒来
// 轮到第3个订单,3时刻开始,用时100万
// 会发现可用流水线已经没有了,此时需要等到流水线A在100万+1时刻醒来,做当前订单
var use *Line
if len(canUseLines) == 0 {
// 如果当前时刻,可以使用的流水线不存在,需要等到可以唤醒的最早那个
// 如果可以唤醒的最早流水线,不只一个
// 选编号小的,看比较器的注释
use = heap.Pop(&sleepLines).(*Line)
ans[i][1] = use.time + componets[jobType]
} else {
// 如果当前时刻,可以使用的流水线存在,需要使用编号最小的
use = heap.Pop(&canUseLines).(*Line)
ans[i][1] = startTime + componets[jobType]
}
ans[i][0] = use.index
use.time = ans[i][1]
heap.Push(&sleepLines, use)
}
return ans
} func randomArray(n, v int) []int {
ans := make([]int, n)
rand.Seed(time.Now().UnixNano())
for i := 0; i < n; i++ {
ans[i] = rand.Intn(v) + 1
}
return ans
} func randomMatrix(n, a, b int) [][]int {
ans := make([][]int, n)
rand.Seed(time.Now().UnixNano())
for i := 0; i < n; i++ {
ans[i] = []int{rand.Intn(a) + 1, rand.Intn(b)}
}
return ans
} func main() {
N := 100
M := 300
V := 10000
testTimes := 5000
fmt.Println("功能测试开始")
for i := 0; i < testTimes; i++ {
nums := rand.Intn(N) + 1
orderNumber := rand.Intn(M) + 1
types := rand.Intn(N) + 1
componets := randomArray(types, V)
orders := randomMatrix(orderNumber, V, types)
sort.Slice(orders, func(i, j int) bool { return orders[i][0] < orders[j][0] })
ans1 := Times1(nums, componets, orders)
ans2 := Times2(nums, componets, orders)
for j := range ans1 {
if ans1[j][0] != ans2[j][0] || ans1[j][1] != ans2[j][1] {
fmt.Println("出错了!")
fmt.Println(nums)
for _, num := range componets {
fmt.Printf("%d ", num)
}
fmt.Println()
for _, order := range orders {
fmt.Printf("(%d, %d) ", order[0], order[1])
}
fmt.Println()
fmt.Print("ans1 : ")
for _, cur := range ans1 {
fmt.Printf("(%d, %d) ", cur[0], cur[1])
}
fmt.Println()
fmt.Print("ans2 : ")
for _, cur := range ans2 {
fmt.Printf("(%d, %d) ", cur[0], cur[1])
}
fmt.Println()
return
}
}
}
fmt.Println("功能测试结束") fmt.Println("性能测试开始")
N = 100000
M = 500000
V = 100000
nums := N
componets := randomArray(N, V)
orders := randomMatrix(M, V, N)
sort.Slice(orders, func(i, j int) bool { return orders[i][0] < orders[j][0] })
fmt.Println("流水线数量 : ", N)
fmt.Println("订单数量 : ", M)
fmt.Println("时间数值范围 : ", V)
start := time.Now()
Times2(nums, componets, orders)
end := time.Now()
fmt.Println("运行时间 : ", end.Sub(start).Milliseconds(), " 毫秒")
fmt.Println("性能测试结束")
}

2022-04-26:给定一个数组componets,长度为A, componets[i] = j,代表i类型的任务需要耗时j 给定一个二维数组orders,长度为M, orders[i][0]代表i的更多相关文章

  1. JS数组 二维数组 二维数组的表示 方法一: myarray[ ][ ];方法二:var Myarr = [[0 , 1 , 2 ],[1 , 2 , 3, ]]

    二维数组 一维数组,我们看成一组盒子,每个盒子只能放一个内容. 一维数组的表示: myarray[ ] 二维数组,我们看成一组盒子,不过每个盒子里还可以放多个盒子. 二维数组的表示: myarray[ ...

  2. 《java入门第一季》二维数组三个案例详解

    案例一:遍历二维数组 /* 需求:二维数组遍历 外循环控制的是二维数组的长度,其实就是一维数组的个数行数. 内循环控制的是一维数组的长度,每一行,一维数组元素分别的个数. */ class Array ...

  3. C/C++二维数组的用法

    二维数组在存储时按行优先连续存储,数组名是一个二维指针,如 int a[3][2] 中,a 是一个二维指针,而a[0],a[1],a[2]都相当于普通的一位数组的数组名,是一个固定值的指针. 二维数组 ...

  4. php对二维数组进行相关操作(排序、转换、去空白等)

    php对二维数组进行相关操作(排序.转换.去空白等) 投稿:lijiao 字体:[增加 减小] 类型:转载 时间:2015-11-04   这篇文章主要介绍了php对二维数组进行相关操作,包括php对 ...

  5. [zt]C++二维数组讲解、二维数组的声明和初始化

    定义: int *pia = new int[10]; // array of 10 uninitialized ints 此 new 表达式分配了一个含有 10 个 int 型元素的数组,并返回指向 ...

  6. Java数组之二维数组

    Java中除了一维数组外,还有二维数组,三维数组等多维数组.本文以介绍二维数组来了解多维数组. 1.二维数组的基础 二维数组的定义:二维数组就是数组的数组,数组里的元素也是数组. 二维数组表示行列二维 ...

  7. Java编程基础阶段笔记 day06 二维数组

    二维数组 笔记Notes 二维数组 二维数组声明 二维数组静态初始化与二位初始化 二维数组元素赋值与获取 二维数组遍历 二维数组内存解析 打印杨辉三角 Arrays工具类 数组中常见的异常 二维数组 ...

  8. (java)剑指offer二维数组中的查找

    在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从 上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. pu ...

  9. 问题 A: 【动态规划】采药_二维数组_一维数组

    问题 A: [动态规划]采药 时间限制: 1 Sec  内存限制: 64 MB提交: 35  解决: 15[提交][状态][讨论版] 题目描述 山洞里有一些不同的草药,采每一株都需要一些时间,每一株也 ...

  10. C++使用VARIANT实现二维数组的操作

    C++使用VARIANT实现二维数组的操作 VARIANT变量是COM组件之间互相通信的重要的参数变量之一,它可以容纳多种不同的类型,如short.long.double等,包括各类指针和数组.组件之 ...

随机推荐

  1. vs2019升级到16.8编译报razortaghelper 任务意外失败的错误

    为了体验.net 5,把vs升级到了最新版本16.8,然后编译原来的项目(.net core 2.2),报了以下错误: 解决方法如下: 删除C:\Program Files\dotnet\sdk\Nu ...

  2. linux使用iperf3测试带宽

    1. https://www.alibabacloud.com/help/zh/express-connect/latest/test-the-performance-of-an-express-co ...

  3. time命令详解

    Linux中time命令,我们经常用来计算某个程序的运行耗时,用户态cpu耗时,系统态cpu耗时. 例如: $ time foo real        0m0.003s user        0m ...

  4. Android笔记--数据存储之SharedPreferences

    SharedPreferences--轻量级存储工具(共享参数) 其采用的存储结构是Key-Value的键值对方式 SharedPreferences用法以及相关的简单案例 记住密码的实现 实现啦! ...

  5. Cesium渲染模块之Command

    1. 引言 Cesium是一款三维地球和地图可视化开源JavaScript库,使用WebGL来进行硬件加速图形,使用时不需要任何插件支持,基于Apache2.0许可的开源程序,可以免费用于商业和非商业 ...

  6. springboot--yaml数据读取的三种方式

    结果:

  7. 基于Vue 使用threejs导入gltf动画模型

    被老师要求学习这个完全不懂的领域的知识,代码东拼西凑终于搞定了,可能写的不好,但这方面的教程很少 某CS**平台的教程都是互相抄,看着烦死. <template> <div id=& ...

  8. Web请求与响应(SpringBoot)

    Web请求与响应 Web的工作原理可以分为以下几个步骤: 输入URL:Web客户端使用Web浏览器输入所需访问的URL(统一资源定位符). 建立连接:Web浏览器与Web服务器之间建立TCP/IP连接 ...

  9. 【责任链设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

    简介 责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,也叫职责链模式.命令链模式.这种模式为请求创建了一个接收者对象的链,允许你将请求沿着处理者链进行 ...

  10. yaml-cpp YAML格式处理库的介绍和使用(面向业务编程-文件格式处理)

    yaml-cpp YAML格式处理库的介绍和使用(面向业务编程-文件格式处理) YAML格式介绍 YAML的格式介绍,有关ini.json和xml或许很多人已经很了解了,但是关于YAML,还有许多人不 ...