LeetCode 课程表III(贪心策略)

这里有 n 门不同的在线课程,他们按从 1 到 n 编号。每一门课程有一定的持续上课时间(课程时间)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 <= 10,000 。
你不能同时修两门课程。

思路分析: 这道题肯定是妥妥的贪心策略题,但是这道题右增加了难度。
首先我们按照(主)结束时间升序,(辅)上课时间进行排序,然后从第一门开始尽量学更多的课程。

class Solution {
public:
	//按照(主)结束时间升序,(辅)上课时间进行排序
	static bool myCmp(vector<int> &courseOne, vector<int> &courseTwo) {
		if (courseOne[1] == courseTwo[1]) {
			return courseOne[0] < courseTwo[0];
		}
		else {
			return courseOne[1] < courseTwo[1];
		}
	}
	int scheduleCourse(vector<vector<int>>& courses) {
		int canCourseCnt = 0, nowDay = 0;//可以学的课程数canCourseCnt ,现在的时间nowDay
		sort(courses.begin(), courses.end(), myCmp);//按照(主)结束时间升序,(辅)上课时间进行排序
		for (auto &course : courses) {
			if (nowDay + course[0] <= course[1]) {//如果这门课能学就尽量学
				canCourseCnt += 1;
				nowDay += course[0];//更新现在的时间
			}
		}
		return canCourseCnt;
	}
};

LeetCode 课程表III(贪心策略)
按照上面的逻辑,排序后为[[5, 5],[2, 6],[4, 6]]我们先学[5,5]到达了第5天,接下来学[2,6]学完这门课已经第7天了,超过了它的结束时间7。蛋式我们可以这样思考,我们可以使用[2,6]这门课区替代[5,5]这门课,因为[5,5]花的时间多,而[2,6]花的时间少。接着我们就能学习[4,6]了,因而答案是2。
辣么问题来了,我们什么时候可以进行替换呢?由于在学习课程之前,我们已经按照了结束时间进行升序排序,那么如果在课程k前有一门课程时间j超过了k的学习时间,则我们这时就能进行替换,因为j的学习时间大,并且k的结束时间晚,可以学习j就一定能学习k。

class Solution {
public:
	//按照(主)结束时间升序,(辅)上课时间进行排序
	static bool myCmp(vector<int> &courseOne, vector<int> &courseTwo) {
		if (courseOne[1] == courseTwo[1]) {
			return courseOne[0] < courseTwo[0];
		}
		else {
			return courseOne[1] < courseTwo[1];
		}
	}
	int scheduleCourse(vector<vector<int>>& courses) {
		int nowDay = 0;
        priority_queue<int> myPriorityQue;//优先队列,降序排列已经学过的课程花费的时间
		sort(courses.begin(), courses.end(), myCmp);//按照(主)结束时间升序,(辅)上课时间进行排序
		for (auto &course : courses) {
			if (nowDay + course[0] <= course[1]) {//这门课可以直接学习(贪心策略)
				nowDay += course[0];
                myPriorityQue.push(course[0]);
			}
            else if (!myPriorityQue.empty() && myPriorityQue.top() > course[0]){//如果这门课的学习时间小于之前学过的最长时间的课,则进行替换,因为这样可以空出更多的时间用来学习后面的课程
                nowDay = nowDay - myPriorityQue.top() + course[0];//回退这门最长的时间的课程,学习当前课程
                myPriorityQue.pop();
                myPriorityQue.push(course[0]);
            }
		}
		return myPriorityQue.size();
	}
};

LeetCode 课程表III(贪心策略)