Job Sequencing Problem

Problem Statement
You are given a set of N jobs, where each job is having a deadline and a profit associated with it. You can only earn a profit if you complete the job within its given deadline. You can perform the job either before the deadline or strictly on the deadline, not after that.
Rules:
- Each job takes a single unit of time to execute
- Only one job can be performed at a given time
Input Format: The jobs will be provided in the form of (Job_id, deadline, profit) associated with that particular Job.
Task: Your task is to find the number of jobs done so as to earn the maximum profit.
Output Format: You are expected to print the number of jobs done and the maximum profit earned by doing them.
Examples
Let us see an example to see what our input and output format will look like.
Example 1:
Input:
Output:
Explanation:
In the above example, the job with job_id = 1 and job with job_id = 4, both have the same deadline, i.e. deadline = 1. As per the given rule, we can perform only one job at a time and within the given deadline. So, we choose the job with job_id = 4 since the profit associated with this job (profit = 40) is more than the one with job_id = 1 (profit = 10).
Next, we choose the job with job_id = 5 and take the profit = 30 associated with it.
Finally, we have two more jobs - job_id = 3 and job_id = 5 with the deadline as deadline = 2. So again, we choose the job that gives us maximum profit, i.e. profit = 20.
Total number of jobs done = 3 Maximum Profit = 40 + 30 + 20 = 90
Example 2:
Input:
Output:
Explanation:
We choose the job with profit = 50. Then, out of three jobs with the same deadline (i.e. deadline = 1), we choose the job with maximum profit = 30. Total number of jobs done = 2 Maximum Profit = 50 + 30 = 80
Constraints
The constraints for the Job Sequencing problem are given below:
Approach 1: Greedy Algorithm
The Job Sequencing problem wants us to find out the maximum profit we will gain by selecting the appropriate jobs within their deadlines. So, after reading the problem statement itself, a greedy approach comes up to our mind.
Just a recap of the Greedy Algorithm:-
Basically, the greedy algorithm deals with the solving of any problem in a greedy manner, i.e. by choosing the best option that is available for us at that particular moment. However, it is not concerned about the final results, i.e. whether our result will be optimal or not by choosing those options.
Strategy:
Our main goal should be to maximize the profit, which can be naturally done by choosing the jobs that give the highest profits.
But how can you efficiently choose the jobs with the highest profit? Well, that can be easily done by sorting the jobs in descending order of profit.
The next thing to note here is, that we must finish the job before or on its deadline. So, at max, we can perform a job on the day of its deadline, which is of utmost preferred. But why?
Because, that will leave some empty slots, which can be utilized later to perform other jobs in certain cases (especially when we have overlapping job deadlines).
Algorithm:
- Sort the jobs in the descending order of the profits
- Create an array of size s, where s = maximum deadline among all the jobs
- Initialize the array with -1, since, we have not scheduled any job initially.
- Run a for loop through every job and choose a slot i if:
- The job i can be performed on the day of its deadline
- Otherwise, loop from deadline -> 1 to find an empty slot where it can be performed
- If a slot is found, mark that slot with the job ID, increment the number of jobs perform, and add its profit to our answer
- Else, go to the next job
Implementation in Python, C++ and Java
C++ Implementation
Below given is the C++ code for the Job Sequencing problem :
Code:
Java Implementation
Below given is the Java code for the Job Sequencing problem :
Python Implementation
Below given is the Python code for the Job Sequencing problem:
Output:
Time Complexity Analysis
As we saw, using the above greedy approach, we are basically performing 2 operations in our given input to solve our job sequencing problem and get the maximum profit. They are as given below --
- Sorting the jobs on the basis of the maximum profit
- Running a loop through all the jobs -> Running another loop inside it from a particular deadline till we get an empty array cell.
So basically, in the first step, for sorting we will require time. And, for running a loop for jobs, we will need time, also, within that, we are running another loop from the deadline till the first element (in the worst case). So for that, suppose we take time. Hence, the two loops together will take time.
So, total time complexity = +
When M becomes greater than or equal to N, then we can say that the worst-case time complexity becomes ()
Space Complexity Analysis
In this problem, we are using an array of the maximum size that is equal to the maximum deadline. Suppose the maximum deadline is , so we will need an array of size . Hence, the total space complexity becomes .
Approach 2 - Using Priority Queue
In the above greedy approach, we saw that our time complexity could get to at the worst. But, hold on! we have another approach that could be our savior in this situation. That is, by using the Priority Queue - (max heap).
But wait, what are priority queues?! Let's recap :)
Basically, priority queues are special types of queues that have a priority attached to them. In simple words, the priority queue gives more priority to the elements with "high priority". For example, it returns them before any low-priority elements. However in some implementations, if two or more elements have the same priority, then they will be returned in the order in which they were inserted (enqueued). Learn more about Priority Queues here in the scaler topics.
Algorithm
The basic approach that we will be using to solve this problem is, will sort the jobs based on the deadline and use a max heap to store the profit, deadline, and job ID of ith job. Let us note down the points we are going to take care which using the priority queue to solve our problem.
- Sort the array on the basis of their deadlines
- Calculate the slot between every two deadlines starting from the end of the array (our Jobs array). The slot calculated must be between consecutive deadlines.
- Include the profits, deadlines, and jobIDs of each of the jobs in the max heap.
- Now, till any of the slots are available and there are still jobs remaining in the max heap, the result should include the ID of the job, as well as its deadline and maximum profit. So, keep on adding them.
- In case you want to know the sequence in which the jobs are executed, then the Arrays of final output are sorted by their deadlines.
Implementing in C++, Java, Python
Let us see the code for each of them in Java, Python and C++.
C++ Implementation
Below given is the C++ code for the Job Sequencing problem.
Code:
Output:
Java Implementation
Below given is the Java code for the Job Sequencing problem.
Code:
Output:
Python Implementation
Below given is the Python code for the Job Sequencing problem. A few important facts to note here are:
-
Python library "heapq" does not have in-built support for maxheap, hence we only have the minheap in Python. But, we can use the "min-heap" in Python as a "max-heap" using simple logic. That is, while inserting the values in the heap if we want our heap to act as a max-heap, we can store the "negative" of the value on the basis of which we want our heap to sort. After that, while fetching the result, we will multiply it with a so as to get back our original value. That will result in the minheap acting as a maxheap.
-
In the below code, we have inserted the negative of the "Profits" in the heap, and while fetching the result, we have again taken the negative of the profit to get back our actual value.
-
Doing so will result in making our min-heap act as a max-heap.
Code:
Output:
Time Complexity Analysis
In this approach, we sort the array which approximately takes a time of O(NlogN). After that, we run a for loop in the backward order of the jobs. From that, we calculate the difference in the deadline and run a loop. The second loop will not run every time since it depends upon the slot available and whether there is an element in the heap or not. Also, we will insert the elements into the heap. Overall, the worst time complexity for these loops will be O(N). So, the total worst-case time complexity for our solution will be O(NlogN + N).
Space Complexity Analysis
In this problem, we are using the heap which will store all the elements in the worst case. Hence, the overall space complexity for the solution becomes O(N)
Approach 3 - Using Sets
In the first approach, we had to iterate through all the jobs for each job and find a job that supports the condition. And, we saw how our time complexity became quadratic - O(). Now, in this approach, we will learn how can we improve that using the sets.
Basically, we will apply the binary search on the sets and find the jobs which will satisfy the conditions.
Our algorithm for solving this problem will be as follows:
- Firstly, you need to sort the jobs based on the descending order of the profits.
- Then, find the maximum deadline for all the jobs
- Create a set, and initialize it with all the jobs in the descending order
- Now, iterate through the job and perform the following operations on it:
- If the set is empty, or the deadline of the current job is less than the last element in the set, simply do not do anything and ignore that job.
- Otherwise, apply the binary search and find the nearest slot 'i', for which i is less than the deadline, and add the profit.
- Also, increment the count of jobs and remove the ith element from the set.
- Finally, return the number of jobs and the maximum profit earned.
Implementation in C++, Java, and Python
C++ Implementation
Below given is the C++ implementation of the Job Sequencing problem.
Code:
Java Implementation
Below given is the Java implementation of the Job Sequencing problem.
Python Implementation
Now let us implement the above approach in Python. Here we can find the nearest Slot i, so that the is less than the deadline by using the bisect in Python. The basic purpose of the bisect in Python is to find a position in the list where an element is to be inserted to keep the overall list sorted.
Output:
Time Complexity Analysis
The worst-case time complexity for the above approach will be . Since will be required for sorting. Apart from that, we run loops for different purposes like finding out the maximum deadline, and the available slot which takes .
Space Complexity
The worst-case time complexity will be . Because we are using an additional set.
Conclusion
In this article, we learned about the Job sequencing Problem and also the different approaches we used to calculate it. Let's take a brief pause and reflect on what we have learned so far!
- In the Job Sequencing problem, we are provided with the Job ID, the deadline of the job, and the profit associated with it. We need to find out the maximum profit we will gain after completing the jobs within the given deadline.
- The first approach we used was using the greedy approach where we sorted the array on the basis of the profits and choose the elements that fell within the deadline, simultaneously calculating the profit for each.
- The second approach was using the priority queue where we inserted the Jobs in the maxheap, and we fetched the jobs based on the highest profit, using the slots. The slots were majorly responsible for keeping track of the difference between deadlines.
- The last approach was to use a set. It considerably improved the overall time complexity by O(NlogN).