LC每日一题|20240515 - 2589. 完成所有任务的最少时间
你有一台电脑,它可以 同时 运行无数个任务。给你一个二维整数数组
tasks,其中tasks[i] = [starti, endi, durationi]表示第i个任务需要在 闭区间 时间段[starti, endi]内运行durationi个整数时间点(但不需要连续)。当电脑需要运行任务时,你可以打开电脑,如果空闲时,你可以将电脑关闭。
请你返回完成所有任务的情况下,电脑最少需要运行多少秒。
提示:
1 <= tasks.length <= 2000tasks[i].length == 31 <= starti, endi <= 20001 <= durationi <= endi - starti + 1
题目等级:Hard
题目评分:2380.60
解题思路
反贪局!
拿到这题我的第一反应是贪心,先把时间点按照「贡献」排序,然后一个个的弹出来去和tasks去匹,最热门的时间用来执行,性价比看起来是最高的了~
但是这样可能会带来两个问题:
- 复杂度蹭蹭的往上窜
- 这样做怎么确保全局最优?
坦白讲有点不敢写了23333
后来还是看了看题目下的评论,有位老哥举了个拖延症的例子...
豁然开朗!
我们可以先把tasks对endTime排序,保证前一个task的endTime小于等于后一个task的endTime。
这样对于后一个task来说,前一个task越「拖延」,对于它是越「有利」的。因为前边的执行时间越靠后,越有可能与自己的执行区间重合。
然后我们开一个数组用于记录「该时间点电脑是否打开」,遍历排序后的tasks并按照下列规则维护时间表:
- 遍历区间
[task[0], task1[1]],如果某一时间已经被前边的任务设定为「打开」,则task[2]--,代表该task在此刻也执行了。 - 如果跑下来之后
task[2] > 0,则说明现在「打开」的时间段是不够的,必须要再开一些时间。这时我们可以倒序遍历时间区间去寻找尚处于「关闭」的时间点「打开」,也就是上文所谓的拖延。
跑完之后数一下时间数组内有多少「打开」的时间点就可以了。
AC代码
class Solution {
fun findMinimumTime(tasks: Array<IntArray>): Int {
val time = BooleanArray(2001)
tasks.sortBy { it[1] }
for (task in tasks) {
for (i in task[0]..task[1]) {
if (time[i]) task[2]--
}
while (task[2] > 0) {
for (i in task[1] downTo task[0]) {
if (!time[i]) {
time[i] = true
task[2]--
}
if (task[2] == 0) break
}
}
}
return time.filter { it }.size
}
}
时间复杂度:O(n^2)
空间复杂度:O(n)