leetcode 630. 课程表 III 贪心

leetcode 630. 课程表 III

题目描述

这里有 n 门不同的在线课程,他们按从 1n 编号。每一门课程有一定的持续上课时间(课程时间)t 以及关闭时间第 d 天。一门课要持续学习 t 天直到第 d 天时要完成,你将会从第 1 天开始。

给出 n 个在线课程用 (t, d) 对表示。你的任务是找出最多可以修几门课。

样例

输入: [[100, 200], [200, 1300], [1000, 1250], [2000, 3200]]
输出: 3
解释: 
这里一共有 4 门课程, 但是你最多可以修 3 门:
首先, 修第一门课时, 它要耗费 100 天,你会在第 100 天完成, 在第 101 天准备下门课。
第二, 修第三门课时, 它会耗费 1000 天,所以你将在第 1100 天的时候完成它, 以及在第 1101 天开始准备下门课程。
第三, 修第二门课时, 它会耗时 200 天,所以你将会在第 1300 天时完成它。
第四门课现在不能修,因为你将会在第 3300 天完成它,这已经超出了关闭日期。

注意

  • 整数 1 <= d, t, n <= 10000。
  • 你不能同时修两门课程。

算法

(贪心,堆) \(O(nlog n)\)

  1. 首先按照终止时间d大小排序。
  2. 考虑两门课的(t1, d1)(t2, d2) 的情况。
    • 如果 t1 + t2 <= d1,则两门课随意安排都可以上。
    • 如果 t1 + t2 > d1 && t1 + t2 <= d2,则上完第一门课后再上第二门课。
    • 如果 t1 + t2 > d2,则两门课只能上一门,这里当然会选择上时间短的那一门,即删除时间最长的一们课。
  3. 推广:f(i)表示前i门课存在最多可以修读的课程数目。
    • 总上课时间sum <= di,第i门课可以可以加入,f(i) = f(i -1) + 1
    • 总上课时间sum > di, 需要删除时间最长的课程,f(i) = f(i - 1)
  4. 具体做法:从头开始遍历课程,维护总的上课时间 sum
    • sum 加上当前课的时间小于等于当前课 i 的结束时间,则直接将课加入到选课列表中,并记录在大根堆里。
    • sum 加上当前课的时间大于当前课 i 的结束时间,则考虑大根堆中耗时最长的课 top,如果 top 的耗时比当前课程 i 要长,则替换为当前课程 i;否则不替换。

时间复杂度

  • 排序时间复杂度为 \(O(n log n)\),枚举课程需要 \(O(n)\),每次访问单调队列需要 \(O(log n)\),故总时间复杂度为 \(O(n log n)\)

C++ 代码

class Solution {
public:
    int f[10010];
    priority_queue<int> heap;
    int scheduleCourse(vector<vector<int>>& courses) {
        sort(courses.begin(), courses.end(), [&](vector<int> &a, vector<int> &b){
            return a[1] < b[1];
        });
        int sum = 0;
        for(auto &c : courses){
            sum += c[0];
            heap.push(c[0]);
            if(sum > c[1]){
                sum -= heap.top();
                heap.pop();
            }
        }
        return heap.size();    
    }
};

dp超时

class Solution {
public:
    int f[10010];
    int scheduleCourse(vector<vector<int>>& courses) {
        sort(courses.begin(), courses.end(), [&](vector<int> &a, vector<int> &b){
            if(a[1] == b[1]) return a[0] < b[0];
            else return a[1] < b[1];
        });
        int n = courses.size();
        int res = 0;
        for(int i = 0; i < n; i++){
            for(int j = courses[i][1]; j >= courses[i][0]; j--){
                f[j] = max(f[j], f[j - courses[i][0]] + 1);
                res = max(res, f[j]);
            }
        }
        return res;    
    }
};
posted @ 2021-12-14 09:11  pxlsdz  阅读(64)  评论(0编辑  收藏  举报