leetcode刷题日记-课程表 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 天完成它,这已经超出了关闭日期。

  • 解析:乍一看,这个题目有点无从下手,但是我们可以简单的先想想[[100, 200], [200, 300]],对于这个数组,我们发现先修lastDay较小的是最优的,但是其实所有这种情况都是最优的,具体的证明以后有机会再讲,这个规律证明虽然不容易,但是基于贪心思想还是很容易理解的。
  • 第二个问题是,好了我知道,两个课程之间的最优解法了,那么多个课程之间,怎么进行迭代呢?我们可以先设置三个变量,total表示当前花费的总时间,di表示当前课程对应的消耗时长,li表示该课程的截止日期,我们会出现两种情况
  • 1:当total + di < =li,表示在目前仍然可以修该课程,可以直接讲该课程加入选修计划
  • 2:当total + di > li,表示目前不可以修该课程,那么我们就直接跳过么?当然不是,我们的目的是修最多的课程,如果当前课程的di小于我们选修课程中最大的dj,同时当前di的li又大于该dj对应的lj,那么我们就需要把选修课程中最大的dj用当前的di替换掉。
  • 到这里,结题思路就出来了,我们首先需要对courses按照lastDay进行排序,然后用一个小根堆来维护当前选修的课程,这样可以更快的得到选修序列的最大值,因为python只有小根堆,每次返回的是最小值,因此我们需要对元素*-1,其实不用也可以,对选修课程进行排序就好,但是这样就会有更大的时间复杂度,小根堆使用一个完全二叉树来维护,寻找最小值的开销极小,下次有机会在讲讲小根堆。
  • 所以这题的考点就是小根堆+贪心,代码如下:
class Solution:
    def scheduleCourse(self, courses: List[List[int]]) -> int:
        """
        给定一门课程列表,列表中包括课程需要时间和最后完成时间,返回能完成的最多课程总
        数,不能同时修两门及以上课程
        >>>self.scheduleCourse([[100, 200], [200, 1300], [1000, 1250], [2000, 3200]]):
        >>>3
        """
        courses.sort(key=lambda x:x[1])
        res = []
        total = 0
        for duration, lastDay in courses:
            if total + duration <= lastDay:
                total += duration
                heapq.heappush(res, -duration)
            else:
                if res and duration < -res[0]:
                    total = total + heapq.heappop(res) + duration
                    heapq.heappush(res, -duration)
        return len(res)

你可能感兴趣的:(算法刷题,leetcode,贪心算法,算法,课程表,小根堆)