630. Course Schedule III

来源:互联网 发布:云计算公司怎么盈利 编辑:程序博客网 时间:2024/06/10 20:20

There are n different online courses numbered from 1 to n. Each course has some duration(course length) t and closed on dthday. A course should be taken continuously for t days and must be finished before or on the dth day. You will start at the 1stday.

Given n online courses represented by pairs (t,d), your task is to find the maximal number of courses that can be taken.

Example:

Input: [[100, 200], [200, 1300], [1000, 1250], [2000, 3200]]Output: 3Explanation: There're totally 4 courses, but you can take 3 courses at most:First, take the 1st course, it costs 100 days so you will finish it on the 100th day, and ready to take the next course on the 101st day.Second, take the 3rd course, it costs 1000 days so you will finish it on the 1100th day, and ready to take the next course on the 1101st day. Third, take the 2nd course, it costs 200 days so you will finish it on the 1300th day. The 4th course cannot be taken now, since you will finish it on the 3300th day, which exceeds the closed date.

Note:

  1. The integer 1 <= d, t, n <= 10,000.
  2. You can't take two courses simultaneously.


思路:最开始想贪心,按照各种排序方法来,但是最后都有些case WA
首先,结束时间早的课程要先考虑,至于选还是不选就是另外一回事,因为如果不这样到后面本来可以选的课程由于deadline过了而变得不能选,这也符合人们的一般逻辑,所以排序规则是先按end time排,相同再按照start time排,越小放在数组越前面
这样的话就能写出递归版本,传2个参数:当前的时间 + 从index为i的课程开设选
import java.util.Arrays;import java.util.Comparator;/* * memo */public class memo {    public int scheduleCourse(int[][] courses) {        Arrays.sort(courses, new Comparator<int[]>(){@Overridepublic int compare(int[] a, int[] b) {return a[1] - b[1];}        });                Integer[][] memo = new Integer[courses.length][courses[courses.length - 1][1] + 1];        return schedule(courses, 0, 0, memo);    }        public int schedule(int[][] courses, int i, int time, Integer[][] memo) {        if (i == courses.length)            return 0;        if (memo[i][time] != null)            return memo[i][time];        int taken = 0;        if (time + courses[i][0] <= courses[i][1])            taken = 1 + schedule(courses, i + 1, time + courses[i][0], memo);        int not_taken = schedule(courses, i + 1, time, memo);        memo[i][time] = Math.max(taken, not_taken);        return memo[i][time];    }}

即使优化为DP版本,复杂度为O(maxTime * length of courses),都会TLE,

其实排完序后可以one pass就解决了,遍历一遍,每次取到当前位置最贪心的情况,何为最贪心?就是选的课程数目最大,在课程数目一样的情况下,结束时间最早(这样就有利于后面的选课),为什么这样贪心是全局最优解呢?假设我们求得i位置的最贪心结果,现在要求i+1位置的最贪心结果
1. 当i+1课程能选我们就先选,贪心使然
2. 如果不能选,我们就尽量把修完课程的时间降到最小(把课程安排的最紧凑),即如果当前课程需要的duration比之前能选的课程最大的duration小,那我们情愿选当前这个,因为这样到目前为止,这样是选课程数目最大,结束时间最早的最优选择(即最贪心的选择),而且一定选的上,因为当前课程结束时间比前面的都大(排过序的),
而且删除之前duration最大也一定只能再加第i+1课程,i+1之前的一定不能加,否则违背之前是最紧凑的贪心情况这一约束

至于怎么快速求出之前最大的duration,用优先队列
/* * greedy & priorityQueue */public class Solution {    public int scheduleCourse(int[][] courses) {        Arrays.sort(courses, new Comparator<int[]>(){@Overridepublic int compare(int[] a, int[] b) {return a[1] - b[1];// 相等再按照默认第一位排序}        });                // 把最大的duration放在顶端,这样当来一个课程放不下时就把最大的duration弹出        PriorityQueue<Integer> pq = new PriorityQueue<Integer>(10, new Comparator<Integer>(){@Overridepublic int compare(Integer o1, Integer o2) {return o2-o1;}        });                int time = 0;        for(int[] c : courses) {        // 能插进pq就插,不能就尽量把pq弄紧凑点        if(time + c[0] <= c[1]) {        pq.add(c[0]);        time += c[0];        } else if(!pq.isEmpty() && pq.peek() > c[0]) {        time += c[0] - pq.poll();        pq.add(c[0]);        }        }                return pq.size();    }}

话说怎么LC有那么详细的解答了






原创粉丝点击