Efficiency is key when it comes to managing multiple jobs with varying start times, end times, and profits. In such scenarios, making the right choices can lead to a significant increase in overall profit. This is where dynamic programming comes to the rescue. In this blog, we’ll explore a Java solution that optimizes job scheduling to maximize profits.

## Understanding the Problem

We have a set of jobs, each represented by its start time, end time, and profit. The challenge is to find the maximum profit we can obtain without scheduling overlapping jobs. If two jobs overlap, we can’t perform both simultaneously.

## The Java Solution

To tackle this problem efficiently, we create a `Job`

class to represent each job’s attributesâ€”start time, end time, and profit. Additionally, we implement a `Solution`

class with the `jobScheduling`

method to find the maximum profit.

### Creating Job Objects

First, we create an array of `Job`

objects, where each object represents a job with its attributes. We populate this array with the data from the input arrays `startTime`

, `endTime`

, and `profit`

.

```
int n = startTime.length;
Job[] jobs = new Job[n];
for (int i = 0; i < n; i++) {
jobs[i] = new Job(startTime[i], endTime[i], profit[i]);
}
```

### Sorting by End Times

To maximize profits and minimize overlaps, we sort the `jobs`

array based on the end times of the jobs. This step is crucial for dynamic programming.

`Arrays.sort(jobs, Comparator.comparingInt(j -> j.endTime));`

### Dynamic Programming

We utilize dynamic programming to find the maximum profit while avoiding overlaps. We initialize an array `dp`

to store the maximum profit for each job up to the current position. We start by setting `dp[0]`

to the profit of the first job.

```
int[] dp = new int[n];
dp[0] = jobs[0].profit;
```

Next, we iterate through the jobs, calculating the current profit and checking for non-overlapping jobs that can contribute to the profit.

```
for (int i = 1; i < n; i++) {
int currentProfit = jobs[i].profit;
int prevNonOverlappingJob = findPrevNonOverlappingJob(jobs, i);
if (prevNonOverlappingJob != -1) {
currentProfit += dp[prevNonOverlappingJob];
}
dp[i] = Math.max(currentProfit, dp[i - 1]);
}
```

The `findPrevNonOverlappingJob`

function helps identify the last non-overlapping job with the current job.

## Full Solution

```
class Job {
int startTime, endTime, profit;
public Job(int startTime, int endTime, int profit) {
this.startTime = startTime;
this.endTime = endTime;
this.profit = profit;
}
}
class Solution {
public int jobScheduling(int[] startTime, int[] endTime, int[] profit) {
int n = startTime.length;
Job[] jobs = new Job[n];
for (int i = 0; i < n; i++) {
jobs[i] = new Job(startTime[i], endTime[i], profit[i]);
}
Arrays.sort(jobs, Comparator.comparingInt(j -> j.endTime));
int[] dp = new int[n];
dp[0] = jobs[0].profit;
for (int i = 1; i < n; i++) {
int currentProfit = jobs[i].profit;
int prevNonOverlappingJob = findPrevNonOverlappingJob(jobs, i);
if (prevNonOverlappingJob != -1) {
currentProfit += dp[prevNonOverlappingJob];
}
dp[i] = Math.max(currentProfit, dp[i - 1]);
}
return dp[n - 1];
}
private int findPrevNonOverlappingJob(Job[] jobs, int currentJobIndex) {
for (int i = currentJobIndex - 1; i >= 0; i--) {
if (jobs[i].endTime <= jobs[currentJobIndex].startTime) {
return i;
}
}
return -1;
}
}
```