LC 6318. 完成所有任务的最少时间
https://leetcode.cn/contest/weekly-contest-336/problems/minimum-time-to-complete-all-tasks/
这题我自己想的是一种很朴素的贪心算法:每次只考虑一个时间点,看这个时间点上有多少任务在上面,选择最对任务的时间点。
代码写出来也不是很复杂,但是我不明白为什么这种贪心有问题。注意下面是错误的答案,这个是我认为正确的写法。
class Solution: def findMinimumTime(self, tasks: List[List[int]]) -> int: S = min((x[0] for x in tasks)) E = max((x[1] for x in tasks)) N = (E - S + 1) TS = set(range(S, E + 1)) ans = 0 while tasks: ev = [] for s, e, d in tasks: ev.append((s, 0)) ev.append((e + 1, 1)) for t in TS: ev.append((t, 2)) ev.sort() d = 0 dm, tm = 0, 0 for ts, ty in ev: if ty == 0: d += 1 elif ty == 1: d -= 1 else: if d > dm: dm = d tm = ts # print('use tm ', tm) TS.remove(tm) ans += 1 tmp = [] for s, e, d in tasks: if s <= tm <= e: d -= 1 if d > 0: tmp.append((s, e, d)) else: tmp.append((s, e, d)) tasks = tmp return ans
看了讨论区里面的解法,还是针对右端进行排序,从最右侧开始安排任务。
我们按照截止时间进行排序,那么我们依次考虑每个事件。为了让其更多地与其他任务共同执行,我们应该 贪心地拖延其完成时间,因为后面的任务截止时期必然比其更靠后,前面的任务只需要贪心往后取运行时间即可。
class Solution: def findMinimumTime(self, tasks: List[List[int]]) -> int: run = [False] * 2001 tasks.sort(key=lambda x: x[1]) for s, e, d in tasks: d -= sum(run[s:e + 1]) # 这段时间内之前已经被安排了多少,这个可以附带上 if d > 0: for t in reversed(range(s, e + 1)): # 剩余的时间从后往前安排 if run[t]: continue d -= 1 run[t] = True if d == 0: break return sum(run)