2023-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("性能测试结束")
}

2023-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. Oracle-安装问题:Win10系统离线安装framework3.5报0x8024402c的问题

    Oracle-安装问题:Win10系统离线安装framework3.5报0x8024402c的问题 像神州信用政府版本相关的系统都不允许联网,也就需要离线安装下,Net3.5之类的文件 具体步骤可以参 ...

  2. 不同时间格式转换问题_python2

    def unix_to_cst(data): """2019-03-17 11:00:00 --> Sun, 17 Mar 2019 11:00:00 GMT+08 ...

  3. Identityserver4 ClientCredentials授权

    转自:https://www.cnblogs.com/hyqq/p/14138024.html:侵删. Client Credentials 客户端应用不代表用户,客户端应用本身就相当于资源所有者 通 ...

  4. java获取前端的token并验证与拦截器

    请求时获取token并验证 public class MyInterceptor implements HandlerInterceptor { //方法执行前进行拦截 @Override publi ...

  5. ssh基于主机名访问

    登录一台服务器我们可以用ssh user@IP这种方式 还有一种快捷的方式,就是基于主机名访问,这需要先配置 /etc/hosts文件 假如我们又两台主机 192.168.75.131/165 分别为 ...

  6. idea application.properties图标显示异常(无小树叶)

    项目中(多级模块)如果没有主启动类时,新建的application.properties文件显示图标是文本格式图标,就如第一张图所示 添加该项目该模块下主启动类,就可以解决图标显示问题,也就可以看到可 ...

  7. day13-SpringBoot整合MyBatis/Plus

    SpringBoot整合MyBatis/Plus 1.SpringBoot整合MyBatis 1.1整合案例 需求:整合SpringBoot和Mybatis,向数据库中查询数据. 项目结构: 1.1. ...

  8. CentOS7环境下数据库运维---主从复制、读写分离

    1.理解MySQL主从复制原理 主服务器开启binlog日志,从库生成log dump线程,将binlog日志传给从库I/O线程,从库生成俩个线程,一个是I/O线程,一个是SQL线程,I/O线程去请主 ...

  9. ChatGPT与码农的机会

    之前一篇博客已经写了有关AI在博客编写方面的优势与对未来博客的编写方面的思考.这篇文档我继续分享一个我在开发中的一个案例和相关的感想. 事件还原 我发现ChatGPT也可以帮助我编写OData,于是我 ...

  10. 基于开源的 ChatGPT Web UI 项目,快速构建属于自己的 ChatGPT 站点

    作为一个技术博主,了不起比较喜欢各种折腾,之前给大家介绍过 ChatGPT 接入微信,钉钉和知识星球(如果没看过的可以翻翻前面的文章),最近再看开源项目的时候,发现了一个 ChatGPT Web UI ...