C++: Maximum Profit in Job Scheduling

Thought Process

The problem requires finding the maximum profit from scheduling non-overlapping jobs. Key observations are that we need to sort jobs by end time to efficiently find non-overlapping ones and use dynamic programming to store intermediate results. For each job, we decide whether to include it (plus profit from last non-overlapping job) or exclude it (carry forward previous profit). Here, binary search helps quickly find the latest non-overlapping job.

class Solution {
public:
    struct Job{

        int startTime;
        int endTime;
        int profit;
    };
    static bool cmp(Job j1, Job j2){
        return j1.endTime < j2.endTime;
    }

    // Will use binary search to find the non overlapping job
    // Returns the latest job that ends before the current job starts.
    int srch(vector<Job> &vJobs, int idx){

        int start = 0;
        int end = idx-1; // As it is 0-based indexing i.e why end=idx-1
        int ans = -1;

        while(start<=end){

            int mid = (start+end)/2;
            // Compare endTime of mid with the startTime of element present idx position
            if(vJobs[mid].endTime <= vJobs[idx].startTime){
                start = mid+1;
                ans = mid;
            }
            else
                end = mid-1;
        }
        return ans;
    }
    int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
        
        int noOfJobs = startTime.size();

        vector<Job> vJobs;
        for(int i=0;i<noOfJobs;i++)
            vJobs.push_back({startTime[i],endTime[i],profit[i]});

        // Sorting by endTime ensures that for any Job i, all possible non-overlapping
        // jobs (ending before ith job) appear before it in sorted order.
        sort(vJobs.begin(),vJobs.end(),cmp);
        int ans[noOfJobs+1]; // ans[i] tells given i jobs, what maximum profit you can make.

        // If there are no jobs, then maxProfit = 0
        ans[0]=0;
        for(int i=1;i<=noOfJobs;i++){

            int include = vJobs[i-1].profit;
            int prevNonOverlappingJob = srch(vJobs,i-1);

            // As prevNonOverlappingJob idx will come as zero based. Therefore, dp state 
            // corresponding to it will be represented by t[prevNonOverlappingJob+1];
            if(prevNonOverlappingJob!=-1)
                include += ans[prevNonOverlappingJob+1];
            
            int exclude = ans[i-1];
            ans[i] = max(include,exclude);
        }
        return ans[noOfJobs];
    }
};
    
/*
Golden Note:

1. Sort by endTime when we need to efficiently find the latest non-overlapping event.
2. Sort by startTime when we merge intervals or checking overlaps.
*/

Code Complexity

Time Complexity: O(n log n)

Sorting takes O(n log n) time and each binary search operation takes O(log n) time for n jobs.

Space Complexity: O(n)

We use O(n) space to store the jobs and the DP array.

Code copied!