Given an array of jobs with different time requirements, where each job consists of start time, end time and CPU load.
The task is to find the maximum CPU load at any time if all jobs are running on the same machine.
Examples:
Input: jobs[] = {{1, 4, 3}, {2, 5, 4}, {7, 9, 6}}
Output: 7
Explanation:
In the above-given jobs, there are two jobs which overlaps.
That is, Job [1, 4, 3] and [2, 5, 4] overlaps for the time period in [2, 4]
Hence, the maximum CPU Load at this instant will be maximum (3 + 4 = 7).
Input: jobs[] = {{6, 7, 10}, {2, 4, 11}, {8, 12, 15}}
Output: 15
Explanation:
Since, There are no jobs that overlaps.
Maximum CPU Load will be – max(10, 11, 15) = 15
This problem is generally the application of the Merge Intervals.
Approach: The idea is to maintain min-heap for the jobs on the basis of their end times. Then, for each instance find the jobs which are complete and remove them from the Min-heap. That is, Check that the end-time of the jobs in the min-heap had ended before the start time of the current job. Also at each instance, find the maximum CPU Load on the machine by taking the sum of all the jobs that are present in the min-heap.
For Example:
Given Jobs be {{1, 4, 3}, {2, 5, 4}, {7, 9, 6}}
Min-Heap - {}
Instance 1:
The job {1, 4, 3} is inserted into the min-heap
Min-Heap - {{1, 4, 3}},
Total CPU Load = 3
Instance 2:
The job {2, 5, 4} is inserted into the min-heap.
While the job {1, 4, 3} is still in the CPU,
because end-time of Job 1 is greater than
the start time of the new job {2, 5, 4}.
Min-Heap - {{1, 4, 3}, {2, 5, 4}}
Total CPU Load = 4 + 3 = 7
Instance 3:
The job {7, 9, 6} is inserted into the min-heap.
After popping up all the other jobs because their
end time is less than the start time of the new job
Min Heap - {7, 9, 6}
Total CPU Load = 6
Maximum CPU Load = max(3, 7, 6) = 7
Below is the implementation of the above approach:
C++
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
class Job {
public :
int start = 0;
int end = 0;
int cpuLoad = 0;
Job( int start, int end, int cpuLoad)
{
this ->start = start;
this ->end = end;
this ->cpuLoad = cpuLoad;
}
};
class MaximumCPULoad {
public :
struct endCompare {
bool operator()( const Job& x, const Job& y)
{
return x.end > y.end;
}
};
static int findMaxCPULoad(vector<Job>& jobs)
{
if (jobs.empty()) {
return 0;
}
sort(jobs.begin(), jobs.end(),
[]( const Job& a, const Job& b) {
return a.start < b.start;
});
int maxCPULoad = 0;
int currentCPULoad = 0;
priority_queue<Job, vector<Job>, endCompare>
minHeap;
for ( auto job : jobs) {
while (!minHeap.empty()
&& job.start > minHeap.top().end) {
currentCPULoad -= minHeap.top().cpuLoad;
minHeap.pop();
}
minHeap.push(job);
currentCPULoad += job.cpuLoad;
maxCPULoad = max(maxCPULoad, currentCPULoad);
}
return maxCPULoad;
}
};
int main( int argc, char * argv[])
{
vector<Job> input
= { { 1, 4, 3 }, { 7, 9, 6 }, { 2, 5, 4 } };
cout << "Maximum CPU load at any time: "
<< MaximumCPULoad::findMaxCPULoad(input) << endl;
}
|
Java
import java.util.*;
class Job {
int start;
int end;
int cpuLoad;
public Job( int start, int end, int cpuLoad) {
this .start = start;
this .end = end;
this .cpuLoad = cpuLoad;
}
};
class MaximumCPULoad {
public static int findMaxCPULoad(List<Job> jobs)
{
Collections.sort(jobs, (a, b) -> Integer.compare(a.start, b.start));
int maxCPULoad = 0 ;
int currentCPULoad = 0 ;
PriorityQueue<Job> minHeap = new PriorityQueue<>(jobs.size(),
(a, b) -> Integer.compare(a.end, b.end));
for (Job job : jobs) {
while (!minHeap.isEmpty() && job.start > minHeap.peek().end)
currentCPULoad -= minHeap.poll().cpuLoad;
minHeap.offer(job);
currentCPULoad += job.cpuLoad;
maxCPULoad = Math.max(maxCPULoad, currentCPULoad);
}
return maxCPULoad;
}
public static void main(String[] args) {
List<Job> input = new ArrayList<Job>(Arrays.asList( new Job( 1 , 4 , 3 ),
new Job( 2 , 5 , 4 ),
new Job( 7 , 9 , 6 )));
System.out.println( "Maximum CPU load at any time: " +
MaximumCPULoad.findMaxCPULoad(input));
input = new ArrayList<Job>(Arrays.asList( new Job( 6 , 7 , 10 ), new Job( 2 , 4 , 11 ), new Job( 8 , 12 , 15 )));
System.out.println( "Maximum CPU load at any time: " +
MaximumCPULoad.findMaxCPULoad(input));
}
}
|
Python3
from heapq import *
class job:
def __init__( self , start,
end, cpu_load):
self .start = start
self .end = end
self .cpu_load = cpu_load
def __lt__( self , other):
return self .end < other.end
def find_max_cpu_load(jobs):
jobs.sort(key = lambda x: x.start)
max_cpu_load, current_cpu_load = 0 , 0
min_heap = []
for j in jobs:
while ( len (min_heap) > 0 and
j.start > = min_heap[ 0 ].end):
current_cpu_load - = min_heap[ 0 ].cpu_load
heappop(min_heap)
heappush(min_heap, j)
current_cpu_load + = j.cpu_load
max_cpu_load = max (max_cpu_load,
current_cpu_load)
return max_cpu_load
if __name__ = = "__main__" :
jobs = [job( 1 , 4 , 3 ), job( 2 , 5 , 4 ),
job( 7 , 9 , 6 )]
print ( "Maximum CPU load at any time: " +
str (find_max_cpu_load(jobs)))
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
public class Job {
public int Start { get ; set ; }
public int End { get ; set ; }
public int CpuLoad { get ; set ; }
public Job( int start, int end, int cpuLoad) {
Start = start;
End = end;
CpuLoad = cpuLoad;
}
}
public class MaximumCpuLoad {
public class EndCompare : IComparer<Job> {
public int Compare(Job x, Job y) {
return x.End.CompareTo(y.End);
}
}
public static int FindMaxCpuLoad(List<Job> jobs) {
if (jobs.Count == 0) {
return 0;
}
jobs = jobs.OrderBy(j => j.Start).ToList();
int maxCpuLoad = 0;
int currentCpuLoad = 0;
var minHeap = new SortedSet<Job>( new EndCompare());
foreach ( var job in jobs) {
while (minHeap.Count > 0 && job.Start > minHeap.First().End) {
currentCpuLoad -= minHeap.First().CpuLoad;
minHeap.Remove(minHeap.First());
}
minHeap.Add(job);
currentCpuLoad += job.CpuLoad;
maxCpuLoad = Math.Max(maxCpuLoad, currentCpuLoad);
}
return maxCpuLoad;
}
}
public class Program {
public static void Main( string [] args) {
var input = new List<Job> {
new Job(1, 4, 3),
new Job(7, 9, 6),
new Job(2, 5, 4)
};
Console.WriteLine( "Maximum CPU load at any time: {0}" , MaximumCpuLoad.FindMaxCpuLoad(input));
}
}
|
Javascript
class Job {
constructor(start, end, cpuLoad) {
this .start = start;
this .end = end;
this .cpuLoad = cpuLoad;
}
};
class MaximumCPULoad
{
static findMaxCPULoad(jobs)
{
jobs.sort((a, b) => a.start - b.start);
let maxCPULoad = 0;
let currentCPULoad = 0;
const minHeap = [];
for (const job of jobs) {
while (minHeap.length > 0 && job.start > minHeap[0].end) {
currentCPULoad -= minHeap.shift().cpuLoad;
}
minHeap.push(job);
currentCPULoad += job.cpuLoad;
maxCPULoad = Math.max(maxCPULoad, currentCPULoad);
}
return maxCPULoad;
}
}
const input = [ new Job(1, 4, 3), new Job(2, 5, 4), new Job(7, 9, 6)];
console.log( "Maximum CPU load at any time: " + MaximumCPULoad.findMaxCPULoad(input));
|
Output
Maximum CPU load at any time: 7
Performance Analysis:
- Time complexity: O(N*logN)
- Auxiliary Space: O(N)
Approach 2:
The idea is simple. We have supposed n intervals, so we have 2n endpoints ( here endpoint is the end of an interval and its value is the time associated with it). We can take an endpoint and combine it with its load value associated with it and with a flag which states whether it is a starting point or ending point of an interval. Then we can just sort the endpoints in increasing order(if there is a tie in value of endpoints then we will break the tie by putting the endpoint which is starting at first place as compared to the endpoint which is ending; if both the endpoints are starting or ending then we will break the tie arbitrarily).
After sorting, we will proceed through the endpoints using for loop. And if we have an endpoint that is the starting point of an interval then we will add the load value associated with it in a variable say, count. We will also take the maximum of the count values and store it in a variable called result.
But when we get an endpoint that is ending then we will decrease the load value associated with it from the count.
At the end, we will return the result.
Lets take an example: suppose the jobs are {1, 4, 3}, {2, 5, 4}, {7, 9, 6}.
our sorted endpoints will be 1(start), 2(start), 4(end), 5(end), 7(start), 9(end) .
and the corresponding loads will be 3, 4, 3, 4, 6, 6.
start traversing the endpoints:
so after traversing first endpoint which is 1(start) we have count+=3 (here 3 is the load associated with it) so count =3. Since the 1 is starting point so we will update the result. So result=max(result,count) so, result=3.
After traversing 2(start) we have count+=4, so count=7, result=max(result,count)=7.
After traversing 4(end) we have count-=3(we have subtracted because it is ending point) so count=4. result will not be updated since we are decreasing the count.
After traversing 5(end) we have count-=4 so count=0.
After traversing 7(start) we have count+=6 so count=6, result=max(result,count)=7.
After traversing 9(end) we have count-=6 so count=0.
Our result will be 7.
C++14
#include <bits/stdc++.h>
using namespace std;
struct Job {
int s, e, load;
};
struct Endpoint {
int val, load;
bool isStart;
};
bool comp( const Endpoint& a, const Endpoint& b) {
if (a.val != b.val)
return a.val < b.val;
return a.isStart == true && b.isStart == false ;
}
int maxCpuLoad(vector<Job> v)
{
int count = 0;
int result = 0;
vector<Endpoint> data;
for ( int i = 0; i < v.size(); i++) {
data.emplace_back(Endpoint{ v[i].s, v[i].load, true });
data.emplace_back(Endpoint{ v[i].e, v[i].load, false });
}
sort(data.begin(), data.end(), comp);
for ( int i = 0; i < data.size(); i++) {
if (data[i].isStart == true ) {
count += data[i].load;
result = max(result, count);
}
else
count -= data[i].load;
}
return result;
}
int main() {
vector<Job> v = {
{6, 7, 10},
{2, 4, 11},
{8, 12, 15}
};
cout << maxCpuLoad(v);
return 0;
}
|
Java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Job {
int s, e, load;
public Job( int s, int e, int load) {
this .s = s;
this .e = e;
this .load = load;
}
}
class Endpoint implements Comparable<Endpoint> {
int val, load;
boolean isStart;
public Endpoint( int val, int load, boolean isStart) {
this .val = val;
this .load = load;
this .isStart = isStart;
}
public int compareTo(Endpoint other) {
if ( this .val != other.val) {
return Integer.compare( this .val, other.val);
}
if ( this .isStart && !other.isStart) {
return - 1 ;
}
if (! this .isStart && other.isStart) {
return 1 ;
}
return 0 ;
}
}
class Main {
static int maxCpuLoad(List<Job> jobs) {
int count = 0 ;
int result = 0 ;
List<Endpoint> data = new ArrayList<>();
for (Job job : jobs) {
data.add( new Endpoint(job.s, job.load, true ));
data.add( new Endpoint(job.e, job.load, false ));
}
Collections.sort(data);
for (Endpoint endpoint : data) {
if (endpoint.isStart) {
count += endpoint.load;
result = Math.max(result, count);
} else {
count -= endpoint.load;
}
}
return result;
}
public static void main(String[] args) {
List<Job> jobs = new ArrayList<>();
jobs.add( new Job( 6 , 7 , 10 ));
jobs.add( new Job( 2 , 4 , 11 ));
jobs.add( new Job( 8 , 12 , 15 ));
System.out.println(maxCpuLoad(jobs));
}
}
|
Python3
class Job:
def __init__( self ,s,e,l) - > None :
self .s = s; self .e = e; self .load = l
class Endpoint:
def __init__( self , v = 0 , l = 0 , isStart = False ) - > None :
self .val = v
self .load = l
self .isStart = isStart
def __lt__( self , other):
if self .val ! = other.val:
return self .val < other.val
return self .isStart = = True and other.isStart = = False
def maxCpuLoad(v):
count = 0
result = 0
data = []
for i in range ( len (v)):
data.append(Endpoint(v[i].s, v[i].load, True ))
data.append(Endpoint(v[i].e, v[i].load, False ))
data.sort()
for i in range ( len (data)):
if data[i].isStart = = True :
count + = data[i].load
result = max (result, count)
else :
count - = data[i].load
return result
if __name__ = = "__main__" :
v = [Job( 6 , 7 , 10 ), Job( 2 , 4 , 11 ), Job( 8 , 12 , 15 )]
print (maxCpuLoad(v))
|
C#
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
class Job {
public int s;
public int e;
public int load;
public Job( int x, int y, int z){
s = x;
y = e;
load = z;
}
}
class Endpoint {
public int val;
public int load;
public bool isStart;
public Endpoint( int x, int y, bool z){
val = x;
load = y;
isStart = z;
}
}
class HelloWorld {
class GFG : IComparer<Endpoint>
{
public int Compare(Endpoint a, Endpoint b)
{
if (a.val != b.val){
if (a.val < b.val) return 1;
else return 0;
}
if (a.isStart == true && b.isStart == false ) return 1;
return 0;
}
}
public static int maxCpuLoad(Job[] v)
{
int count = 0;
int result = 0;
List<Endpoint> data = new List<Endpoint>();
for ( int i = 0; i < v.Length; i++) {
data.Add( new Endpoint(v[i].s, v[i].load, true ));
data.Add( new Endpoint(v[i].e, v[i].load, false ));
}
GFG gg = new GFG();
data.Sort(gg);
for ( int i = 0; i < data.Count; i++) {
if (data[i].isStart == true ) {
count += data[i].load;
result = Math.Max(result, count);
}
else
count -= data[i].load;
}
return result;
}
static void Main() {
Job[] v = new Job[3];
v[0] = new Job(6, 7, 10);
v[1] = new Job(2, 4, 11);
v[2] = new Job(8, 12, 15);
Console.WriteLine(maxCpuLoad(v));
}
}
|
Javascript
<script>
class Job{
constructor(s,e,l){
this .s = s; this .e = e; this .load = l
}
}
class Endpoint{
constructor(v = 0, l = 0, isStart = false ){
this .val = v
this .load = l
this .isStart = isStart
}
}
function comp(a, b) {
if (a.val != b.val)
return a.val - b.val;
return a.isStart == true && b.isStart == false ;
}
function maxCpuLoad(v){
let count = 0
let result = 0
let data = []
for (let i = 0; i < v.length; i++){
data.push( new Endpoint(v[i].s, v[i].load, true ))
data.push( new Endpoint(v[i].e, v[i].load, false ))
}
data.sort(comp)
for (let i = 0; i < data.length; i++)
{
if (data[i].isStart == true ){
count += data[i].load
result = Math.max(result, count)
}
else
count -= data[i].load
}
return result
}
let v = [ new Job(6, 7, 10), new Job(2, 4, 11), new Job(8, 12, 15)]
document.write(maxCpuLoad(v), "</br>" )
</script>
|
Time Complexity: O(nlogn) for sorting the data array.
Auxiliary Space: O(n) which is the size of the data array
Last Updated :
28 Feb, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...