课程表III
这里有 n 门不同的在线课程,按从 1 到 n 编号。给你一个数组 courses ,其中 courses[i] = [durationi, lastDayi] 表示第 i 门课将会 持续 上 durationi 天课,并且必须在不晚于 lastDayi 的时候完成。
你的学期从第 1 天开始。且不能同时修读两门及两门以上的课程。
返回你最多可以修读的课程数目。 示例:
输入:courses = [[100, 200], [200, 1300], [1000, 1250], [2000, 3200]]
输出:3
解释:
这里一共有 4 门课程,但是你最多可以修 3 门:
首先,修第 1 门课,耗费 100 天,在第 100 天完成,在第 101 天开始下门课。
第二,修第 3 门课,耗费 1000 天,在第 1100 天完成,在第 1101 天开始下门课程。
第三,修第 2 门课,耗时 200 天,在第 1300 天完成。
第 4 门课现在不能修,因为将会在第 3300 天完成它,这已经超出了关闭日期。
思路
我们先根据「结束时间」对 courses 排升序,从前往后考虑每个课程,处理过程中维护一个总时长 sum,对于某个课程 courses[i]c 而言,根据如果学习该课程,是否满足「最晚完成时间」要求进行分情况讨论:
学习该课程后,满足「最晚完成时间」要求,即 sum+courses[i][0]<=courses[i][1],则进行学习;
学习该课程后,不满足「最晚完成时间」要求,此时从过往学习的课程中找出「持续时间」最长的课程进行「回退」操作(这个持续时长最长的课程有可能是当前课程)。
其中「记录当前已选课程」和「从过往学习的课程中找出持续时间最长的课程」操作可以使用优先队列(大根堆)实现。
解法一:
def scheduleCourse(self, courses: List[List[int]]) -> int:
courses.sort(key=lambda c: c[1])
queue = list()
count = 0
for ti,di in courses:
if count + ti <= di:
count += ti
heapq.heappush(queue, -ti) # 默认是小根堆
elif queue and -queue[0] > ti:
count -= -queue[0] - ti
heapq.heappop(queue)
heapq.heappush(queue, -ti)
return len(queue)