LeetCode-2589. 完成所有任务的最少时间【栈 贪心 数组 二分查找 排序】
- 题目描述:
- 解题思路一:贪心+暴力
- 解题思路二:栈+二分查找
- 解题思路三:简化版
题目描述:
你有一台电脑,它可以 同时 运行无数个任务。给你一个二维整数数组 tasks ,其中 tasks[i] = [starti, endi, durationi] 表示第 i 个任务需要在 闭区间 时间段 [starti, endi] 内运行 durationi 个整数时间点(但不需要连续)。
当电脑需要运行任务时,你可以打开电脑,如果空闲时,你可以将电脑关闭。
请你返回完成所有任务的情况下,电脑最少需要运行多少秒。
示例 1:
输入:tasks = [[2,3,1],[4,5,1],[1,5,2]]
输出:2
解释:
- 第一个任务在闭区间 [2, 2] 运行。
- 第二个任务在闭区间 [5, 5] 运行。
- 第三个任务在闭区间 [2, 2] 和 [5, 5] 运行。
电脑总共运行 2 个整数时间点。
示例 2:
输入:tasks = [[1,3,2],[2,5,3],[5,6,2]]
输出:4
解释:
- 第一个任务在闭区间 [2, 3] 运行
- 第二个任务在闭区间 [2, 3] 和 [5, 5] 运行。
- 第三个任务在闭区间 [5, 6] 运行。
电脑总共运行 4 个整数时间点。
提示:
1 <= tasks.length <= 2000
tasks[i].length == 3
1 <= starti, endi <= 2000
1 <= durationi <= endi - starti + 1
解题思路一:贪心+暴力
三个关键点。1. 按区间右端点排序。2. 把任务尽可能安排在区间的后缀。3. 用数组记录任务的执行情况
class Solution:def findMinimumTime(self, tasks: List[List[int]]) -> int:tasks.sort(key = lambda x: x[1]) # 排序run = [False] * (tasks[-1][1] + 1) # 初始化确定哪些时间运行的数组for s, e, d in tasks:d -= sum(run[s: e + 1]) # 去掉运行中的时间点if d <= 0: # 该任务已完成continuefor i in range(e, s-1, -1): # 标记需要运行的时间点if run[i]:continuerun[i] = Trued -= 1if d == 0:breakreturn sum(run)
时间复杂度:O(nM)其中 n 是 tasks 的大小,M 是 tasks 的时间段右端点 end 的最大值。
空间复杂度:O(logn + M) 排序和记录的数组
解题思路二:栈+二分查找
class Solution:def findMinimumTime(self, tasks: List[List[int]]) -> int:tasks.sort(key=lambda t: t[1])# 栈中保存闭区间左右端点,栈底到栈顶的区间长度的和st = [(-2, -2, 0)] # 哨兵,保证不和任何区间相交for start, end, d in tasks:_, r, s = st[bisect_left(st, (start,)) - 1]d -= st[-1][2] - s # 去掉运行中的时间点if start <= r: # start 在区间 st[i] 内d -= r - start + 1 # 去掉运行中的时间点if d <= 0:continuewhile end - st[-1][1] <= d: # 剩余的 d 填充区间后缀l, r, _ = st.pop()d += r - l + 1 # 合并区间st.append((end - d + 1, end, st[-1][2] + d))return st[-1][2]
时间复杂度:O(nlogn)
空间复杂度:O(n)
解题思路三:简化版
class Solution:def findMinimumTime(self, tasks: List[List[int]]) -> int:tasks.sort(key = lambda x: x[1])run = [False] * (tasks[-1][1] + 1)for s, e, d in tasks:d -= sum(run[s: e + 1]) # 先减去已经运行的时间if d <= 0: # 已经okcontinuefor i in range(e, s - 1, -1): # 还没okif run[i]:continuerun[i] = Trued -= 1if d == 0:breakreturn sum(run)
时间复杂度:O(nM)其中 n 是 tasks 的大小,M 是 tasks 的时间段右端点 end 的最大值。
空间复杂度:O(logn + M) 排序和记录的数组
♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠ ⊕ ♠