630 Course Schedule III

There are n different online courses numbered from 1 to n. Each course has some duration(course length) t and closed on dth day. A course should be taken continuously for t days and must be finished before or on the dth day. You will start at the 1st day.
Given n online courses represented by pairs (t,d), your task is to find the maximal number of courses that can be taken.
Input: [[100, 200], [200, 1300], [1000, 1250], [2000, 3200]]
Output: 3
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.
  • The integer 1 <= d, t, n <= 10,000.
  • You can't take two courses simultaneously.
The Idea: The general idea is to fit the largest number of courses you can take such that it fits the smallest deadline. I have used a recursive approach, but it quickly fails to stack overflow (albiet if python optimized tail end recursion, it would not). First sort by the courses by deadline. Next, iterate through the courses, by deadline one by one and to find the first available largest course that fits in with the current deadline. We can do this by just again, iterating through the courses in the reverse order of the deadlines. All at the same time, we keep track of the current day we are in. If this course is found, then we can remove said course, update our current day, and do this process again. This next process would again, find the longest course that is before the smallest deadline.
def scheduleCourse(self, courses):
:type courses: List[List[int]]
:rtype: int
by_dead_line = sorted(courses, key=lambda x: -x[1])
return self._scheduleCourse(by_dead_line, 0)
def _get_nxt_lrgst_course(self, by_deadline, current, b4):
# iterate through by duraction - grab first largest
# available course that is within the bounds of the
# current deadline
for i, course in enumerate(reversed(by_deadline)):
if current + course[0] <= b4:
return i
return None
def _scheduleCourse(self, by_dead, cur_day):
for i, course in enumerate(by_dead):
i_next = self._get_nxt_lrgst_course(by_dead, cur_day, course[1])
if i_next is not None:
duration = by_dead[len(by_dead) - i_next - 1][0]
del by_dead[len(by_dead) - i_next - 1]
return 1 + self._scheduleCourse(by_dead, cur_day + duration)
return 0