这里有 n 门不同的在线课程,按从 1 到 n 编号。给你一个数组 courses ,其中 courses[i] = [durationi, lastDayi] 表示第 i 门课将会 持续 上 durationi 天课,并且必须在不晚于 lastDayi 的时候完成。
你的学期从第 1 天开始。且不能同时修读两门及两门以上的课程。
返回你最多可以修读的课程数目。
示例 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 天完成它,这已经超出了关闭日期。
示例 2:
输入: courses = [[1,2]]
输出: 1
示例 3:
输入: courses = [[3,2],[4,3]]
输出: 0
提示:
1 <= courses.length <= 10^41 <= durationi, lastDayi <= 10^4
思路
本题使用队列优先 + 贪心算法求解。对于两门课程[t1,d1] 和[t2, d2], 如果 d1 <= d2, 那么我们应该优先学习前者,再学习后者,总是最优解。
我们先对课程按照关闭时间升序排序,再遍历所有课程。用 q 来保存第 i 门课程之前可修的最多课程,q 中按照课程用时排序,用 total 保存 q 之和。当我们遍历到了第i门课程[ti, di], 此时 total += ti, 把ti插入到q中合适的位置,如果total > di 说明选择是不合法的,我们需要从我们选择的课程中来移除一些课程,移除哪些课程呢?当然是耗时最长的课程了 total -= q.pop(),再接着往下遍历。
解题
/**
* @param {number[][]} courses
* @return {number}
*/
var scheduleCourse = function (courses) {
courses.sort((a, b) => a[1] - b[1]);
const q = [];
const bf = (value) => {
let l = 0;
let r = q.length - 1;
while (l <= r) {
const m = (l + r) >> 1;
if (q[m] > value) {
r = m - 1;
} else if (q[m] < value) {
l = m + 1;
} else {
return m;
}
}
return l;
};
let total = 0;
for (let i = 0; i < courses.length; i++) {
total += courses[i][0];
let idx = bf(courses[i][0]);
q.splice(idx, 0, courses[i][0]);
if (total > courses[i][1]) {
total -= q.pop();
}
}
return q.length;
};