Notion에서 작성한 글이라, 여기에서 더 깔끔하게 보실 수 있습니다! 😮😊
[Maximum Profit in Job Scheduling]
startTime
, endTime
, profit
을 묶어서 끝나는 시간을 기준으로 정렬을 해 보았는데,endTime
이 빠른 순으로 정렬해서 그리디하게 최대한 많은 job을 선택했을 때, endTime
이 느린 job이 endTime
이 빠른 job을 포기해도 될 만큼 profit
이 높을 수 있다.startTime
또는 endTime
을 정렬해 주고 나면(고정해 주고 나면), 이 문제와 완전히 유사한 구조가 되어버린다. (스포) 이 문제에서는 1일, 2일, 3일과 같이 로 기간을 다루어 갱신을 했지만,startTime
을 기준으로 정렬했을 때), 현재 작업이 시작되기 이전 가장 나중의 작업을 찾아서 갱신을 하면 된다(endTime
을 기준으로 정렬했을 때).startTime
과, endTime
중 어떤 걸 기준으로 정렬해야 할까? 위에서 잠깐 언급했지만 구현만 다를 뿐 상관이 없다.startTime
을 기준으로 정렬하고, 그 작업이 끝나는 시간 이후의 첫 작업을 찾는다. 이 때, 으로 탐색하는 것이 아닌, startTime
이 정렬되어있다는 점을 생각하면 이분 탐색을 이용하여 으로 아주 빠르게 그 작업을 찾을 수 있게 된다.endTime
을 기준으로 정렬하고, 현재 작업의 startTime
이전에 끝나는 마지막 작업을 찾는다. 이 때, 으로 탐색하는 것이 아닌, endTime
이 정렬되어있다는 점을 생각하면 이분 탐색을 이용하여 으로 아주 빠르게 그 작업을 찾을 수 있게 된다.[0]
을 추가로 포함시켜 주면 경계 조건을 깔끔하게 처리할 수 있게 된다.def bs_lb(a, v):
lo, hi = 0, len(a)-1
while lo <= hi:
mid = (lo+hi)//2
if a[mid][0] < v:
lo = mid+1
else:
hi = mid-1
return lo
def jobScheduling(startTime, endTime, profit):
schedules = sorted(zip(startTime, endTime, profit), key=lambda x: x[0])
n = len(schedules)
dp = [0]*(n+1)
for i in range(n-1, -1, -1):
s, e, p = schedules[i]
nxt = bs_lb(schedules, e)
dp[i] = max(dp[i+1], p + dp[nxt])
return dp[0]
def bs_ub(a, v):
lo, hi = 0, len(a)-1
while lo <= hi:
mid = (lo+hi)//2
if a[mid][1] <= v:
lo = mid+1
else:
hi = mid-1
return lo
def jobScheduling(startTime, endTime, profit):
schedules = sorted(zip(startTime, endTime, profit), key=lambda x: x[1])
n = len(schedules)
dp = [0]*(n+1)
for i in range(1, n+1):
s, e, p = schedules[i-1]
prev = bs_ub(schedules, s)
dp[i] = max(dp[i-1], p + dp[prev])
return dp[n]
Memo