课程表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)

参考解题

宫水三叶题解