課程排程問題:LeetCode 630. Course Schedule III
阿新 • • 發佈:2019-02-18
題目描述:
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
解題思路:
- 將課程按due time排序,due time排序在前的表示優先順序較高,需要先完成;
- 遍歷排序後的課程,若某個課程可在due time前結束,則將該課程的耗費時間加入排程list中,並更新已花費的時間consumingTIme的值;
- 若某個課程不可在due time前結束,則首先判斷該課程耗費時間是否比list中最長的耗費時間還要長,若是,則不新增該課程;若不是,則刪除list中最長的耗費時間並將該時間加入list中。
原理:
- 按due time排序可保證所有課程較好的時間順序加入list; 若出現某個課程A的due time較小,但consuming time較長的課程,該課程會慢慢被後續consuming time較短的課程B替換掉;
- 且因為B的due time(d1)都比A的due time (d2)大,B的consuming time(c1)都比A的consuming time(c2)小;
- 且A在list中,所以當前時間+c2 < d2,那麼當前時間+c1< d1肯定成立。所以B肯定可以替換A,且可以使得當前時間變小。所以這是一個最優策略。
原始碼
class Solution(object):
def scheduleCourse(self, courses):
#用於查詢list中的元素//二分查詢
def findElement(l, s, e, x):
if s > e:
return s
mid = int((s + e) / 2)
if l[mid] < x:
if mid == len(l) - 1:
return mid + 1
if l[mid + 1] >= x:
return mid + 1
return findElement(l, mid + 1, e, x)
if l[mid] > x:
if mid == 0:
return 0
if l[mid - 1] <= x:
return mid
return findElement(l, s, mid - 1, x)
return mid
if courses == []:
return 0
#按照結束時間排序
courses.sort(key = lambda x : x[1])
res = [courses[0][0]]
#已花去的時間
consumingTimes = res[0]
for i in courses[1:]:
#若課程可在due time前完成,則直接加入list
if consumingTimes + i[0] <= i[1]:
pos = findElement(res, 0, len(res) - 1, i[0])
if pos == len(res):
res.append(i[0])
else:
res.insert(pos, i[0])
consumingTimes += i[0]
#否則若該課程耗費時間較少,則替換list中耗費時間最長的課程
else:
if i[0] < res[-1]:
consumingTimes += i[0] - res[-1]
del res[-1]
pos = findElement(res, 0, len(res) - 1, i[0])
if pos == len(res):
res.append(i[0])
else:
res.insert(pos, i[0])
return len(res)