Problem
We have n
jobs, where every job is scheduled to be done from startTime[i]
to endTime[i]
, obtaining a profit of profit[i]
.
You’re given the startTime
, endTime
and profit
arrays, return the maximum profit you can take such that there are no two jobs in the subset with overlapping time range.
If you choose a job that ends at time X
you will be able to start another job that starts at time X
.
Examples
Example 1:
gantt title Jobs dateFormat X axisFormat %s section Job 4 profit = 70 : 3, 6 section Job 3 profit = 40 : 3, 5 section Job 2 profit = 10 : 2, 4 section Job 1 profit = 50 : 1, 3
|
|
Example 2:
gantt title Jobs dateFormat X axisFormat %s section Job 5 profit = 60 : 6, 9 section Job 4 profit = 70 : 4, 6 section Job 3 profit = 100 : 3, 10 section Job 2 profit = 20 : 2, 5 section Job 1 profit = 20 : 1, 3
|
|
Example 3:
gantt title Jobs dateFormat X axisFormat %s section Job 3 profit = 6 : 1, 4 section Job 2 profit = 6 : 1, 3 section Job 1 profit = 5 : 1, 2
|
|
Solution
Method 1 - DP + Binary Search
We have already seen the Interval Scheduling Problem where the weight of each job is 1
.
The simple activity selection problem can be seen as a specialized case of the weighted activity selection problem where the weight is always 1
. Now, let’s delve into the generalized weighted activity selection problem.
From Wikipedia, the generalized version of the activity selection problem involves selecting an optimal set of non-overlapping activities to maximize the total weight. While the unweighted version can be solved using a greedy algorithm in O(n log n)
time, the same straightforward greedy approach doesn’t work for the weighted version because it involves optimizing weights (or profits).
For example, suppose we have n=4 jobs {1, 2, 3, 4} with the following start and finish time and weights:
gantt title Jobs dateFormat X axisFormat %s section Job 4 profit = 70 : 3, 6 section Job 3 profit = 40 : 3, 5 section Job 2 profit = 10 : 2, 4 section Job 1 profit = 50 : 1, 3
Let’s sort and label the jobs by finishing time: f1 ≤ f2 ≤ … ≤ fN. In order to maximize profit we can either take current job j and include to optimal solution or not include current job j to optimal solution. How to find the profit including current job? The idea is to find the latest job before the current job (in sorted array) that doesn’t conflict with current job 1<=j<=N-1. Once we find such a job, we recur for all jobs till that job and add profit of current job to result.
Lets define qj = largest index i < j such that job i is compatible with j.. For example - q7 = 3, q2 = 0.
Optimal Substructure
Let MAX_PROFIT(j) = value of optimal solution to the problem consisting of job requests {1, 2, … , j }.
- Case 1: MAX_PROFIT selects job j.
- can’t use incompatible jobs { qj + 1, qj + 2, . . . , j-1 }
- must include optimal solution to problem consisting of remaining compatible jobs { 1, 2, . . . , qj }
- Case 2: MAX_PROFIT does not select job j.
- must include optimal solution to problem consisting of remaining compatible jobs { 1, 2, . . . , j - 1 }
|
|
Approach
Here is the approach:
- Job Representation:
- Combine the
startTime
,endTime
, andprofit
arrays into a list of jobs where each job is a tuple (start, end, profit).
- Combine the
- Sort Jobs:
- Sort the jobs based on their end times. This ensures that we process each job in the order they complete, facilitating the use of binary search to find the latest non-overlapping job.
- Dynamic Programming Table:
- Use a dynamic programming array
dp
wheredp[i]
represents the maximum profit achievable by considering jobs up to thei-th
job. - For each job
i
, use binary search to find the latest jobj
that does not overlap with jobi
and updatedp[i]
as the maximum of not including jobi
(i.e.,dp[i-1]
) or including jobi
(i.e.,profit[i] + dp[j]
).
- Use a dynamic programming array
- Binary Search:
- Perform binary search to efficiently find the latest job that does not overlap with the current job.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n log n)
- Sorting the jobs:
O(n log n)
- Building the
dp
array with binary search for each job:O(n log n)
- Overall:
O(n log n)
- Sorting the jobs:
- 🧺 Space complexity:
O(n)
for storing the jobs anddp
array