# Maximum Profit in Job Scheduling

## 1. Clarify the problem:

Before we begin, let's clarify the problem statement. The "Maximum Profit in Job Scheduling" problem asks us to find the maximum profit we can achieve by scheduling jobs within a given time range. Each job has a start time, end time, and profit.

## 2. Analyze the problem:

Let's analyze the problem to identify the input, output, and constraints.

**Input:**

- An array of job start times, denoted by a list
`startTime`

. - An array of job end times, denoted by a list
`endTime`

. - An array of job profits, denoted by a list
`profit`

.

Note: The three input lists are of the same length, and the indices correspond to the same job.

**Output:**

- The maximum profit that can be achieved by scheduling the jobs within the given time range.

**Constraints:**

- 1 <= len(startTime) = len(endTime) = len(profit) <= 5 * 10^4
- 1 <= startTime[i] < endTime[i] <= 10^9
- 1 <= profit[i] <= 10^4
- The start times are sorted in ascending order.

## 3. Design an algorithm:

To solve this problem efficiently, we can use a dynamic programming approach. Here's the general outline of our algorithm:

- Create a list of jobs, where each job is represented by a tuple containing the start time, end time, and profit.
- Sort the list of jobs based on the end times in ascending order.
- Create a list,
`dp`

, of length n (the number of jobs), initialized with 0 values.`dp[i]`

will store the maximum profit achievable up to the i-th job. - Iterate over each job from the sorted list:
- Find the index,
`prev`

, of the last job whose end time is less than or equal to the current job's start time. - Calculate the maximum profit achievable by including the current job or excluding it:
`include_profit = dp[prev] + job[2]`

(profit of the current job plus the maximum profit achievable before the current job)`exclude_profit = dp[i-1]`

(maximum profit achievable without including the current job)

- Update
`dp[i]`

with the maximum of`include_profit`

and`exclude_profit`

.

- Find the index,
- Return the maximum profit stored in
`dp[-1]`

.

## 4. Explain your approach:

Our approach involves using dynamic programming to calculate the maximum profit achievable by scheduling the jobs. We sort the jobs based on their end times and use a dynamic programming table, `dp`

, to store the maximum profit at each step. By iteratively considering each job and calculating the maximum profit achievable with or without including it, we can obtain the maximum profit achievable overall.

## 5. Write clean and readable code:

Let's implement the algorithm in Python:

python

```
def jobScheduling(startTime, endTime, profit):
jobs = sorted(zip(startTime, endTime, profit), key=lambda x: x[1])
n = len(jobs)
dp = [0] * n
for i in range(n):
include_profit = jobs[i][2]
prev = binary_search(jobs, i)
if prev != -1:
include_profit += dp[prev]
exclude_profit = dp[i-1] if i > 0 else 0
dp[i] = max(include_profit, exclude_profit)
return dp[-1]
def binary_search(jobs, current):
low, high = 0, current - 1
while low <= high:
mid = low + (high - low) // 2
if jobs[mid][1] <= jobs[current][0]:
if jobs[mid + 1][1] <= jobs[current][0]:
low = mid + 1
else:
return mid
else:
high = mid - 1
return -1
```

## 6. Test your code:

Let's test our code with different test cases to ensure its correctness. We'll consider the following cases:

Case 1:

python

```
startTime = [1, 2, 3, 4, 6]
endTime = [3, 5, 10, 6, 9]
profit = [20, 20, 100, 70, 60]
```

The expected output is 150.

Case 2:

python

```
startTime = [1, 2, 3, 3, 4, 5]
endTime = [3, 4, 5, 6, 7, 9]
profit = [10, 40, 30, 50, 20, 10]
```

The expected output is 90.

Case 3:

python

`startTime = [1, 2, 3, 4, 6] endTime = [3, 5, 9, 6, 9] profit = [20, 20, 100, 70, 60]`

The expected output is 120.

## 7. Optimize if necessary:

The current implementation already provides an efficient solution to the problem. However, we can optimize the binary search by using the built-in bisect module in Python.

## 8. Handle error cases:

The given problem constraints do not mention any invalid inputs or error cases, so we can assume that the input lists are always valid and adhere to the constraints.

## 9. Discuss complexity analysis:

The time complexity of our solution is O(nlogn), where n is the number of jobs. This is because we sort the jobs based on their end times, which takes O(nlogn) time. The iteration over the sorted list takes O(n) time, and the binary search operation takes O(logn) time.

The space complexity is O(n) since we use a dynamic programming table, `dp`

, of size n to store the maximum profits at each step.

In terms of complexity trade-offs, our approach sacrifices some space to achieve a more efficient time complexity by sorting the jobs and using dynamic programming to calculate the maximum profits.