zoukankan      html  css  js  c++  java
  • [Coding Made Simple / LeetCode 1235] Maximum Profit in Job Scheduling

    Given certain jobs with start and end time and amount you make on finishing the job, find the maximum value you can make by scheduling jobs in non-overlapping way.

    Dynamic programming solution. O(N^2) runtime, O(N) space

    First sort all the jobs in ascending order based on their end time. This makes checking if two jobs overlap or not easier. 

    State: maxGain[i]: Given the first i jobs, the max profit we can get by selecting jobs[i]. 

    Function: maxGain[i] = max {maxGain[i], maxGain[j] + jobs[i].gain}, for j in [0, i)

    Initialization: maxGain[i] = jobs[i].gain, as we know by selecting jobs[i], we at least have a profit of jobs[i].gain.

    Answer:  the max value of maxGain[i]. 

     1 import java.util.Arrays;
     2 
     3 class Job implements Comparable<Job>{
     4     int start;
     5     int end;
     6     int gain;
     7     Job(int start, int end, int gain) {
     8         this.start = start;
     9         this.end = end;
    10         this.gain = gain;
    11     }
    12     public int compareTo(Job o) {
    13         return this.end - o.end;
    14     }
    15 }
    16 public class WeightedJobScheduling {
    17     public int getMaxGain(Job[] jobs) {
    18         Arrays.sort(jobs);
    19         int[] maxGain = new int[jobs.length];
    20         for(int i = 0; i < maxGain.length; i++) {
    21             maxGain[i] = jobs[i].gain;
    22         }
    23         for(int i = 1; i < maxGain.length; i++) {
    24             for(int j = 0; j < i; j++) {
    25                 if(jobs[i].start >= jobs[j].end) {
    26                     maxGain[i] = Math.max(maxGain[i], maxGain[j] + jobs[i].gain);
    27                 }
    28             }
    29         }
    30         
    31         int max = Integer.MIN_VALUE;
    32         for(int i = 0; i < maxGain.length; i++) {
    33             if(maxGain[i] > max) {
    34                 max = maxGain[i];
    35             }
    36         }
    37         return max;
    38     }
    39 }

    This is the same problem with https://leetcode.com/problems/maximum-profit-in-job-scheduling/

    We have n jobs, where every job is scheduled to be done from startTime[i] to endTime[i], obtaining a profit of profit[i].

    You're given the startTime , endTime and profit arrays, you need to output the maximum profit you can take such that there are no 2 jobs in the subset with overlapping time range.

    If you choose a job that ends at time X you will be able to start another job that starts at time X.

    Example 1:

    Input: startTime = [1,2,3,3], endTime = [3,4,5,6], profit = [50,10,40,70]
    Output: 120
    Explanation: The subset chosen is the first and fourth job. 
    Time range [1-3]+[3-6] , we get profit of 120 = 50 + 70.
    

    Example 2:

    Input: startTime = [1,2,3,4,6], endTime = [3,5,10,6,9], profit = [20,20,100,70,60]
    Output: 150
    Explanation: The subset chosen is the first, fourth and fifth job. 
    Profit obtained 150 = 20 + 70 + 60.
    

    Example 3:

    Input: startTime = [1,1,1], endTime = [2,3,4], profit = [5,6,4]
    Output: 6
    

    Constraints:

    • 1 <= startTime.length == endTime.length == profit.length <= 5 * 10^4
    • 1 <= startTime[i] < endTime[i] <= 10^9
    • 1 <= profit[i] <= 10^4

    Given the input size of 5 * 10^4, the previous O(N^2) solution is too slow. The bottleneck is that the O(N^2) solution requires O(N) time to find the maximum job profit from 0 to i - 1 jobs that does not overlap with the ith job. Since we already sorted all the jobs based on their end time, we know that for two index j and k, if j < k, if the kth job does not overlap the ith job, the jth job does not overlap with the ith job either. If we can make sure that the biggest index of j < i gives us the max profit from scheduling 0 to jth jobs, we can apply binary search to speed up the runtime from O(N) to O(logN). 

    We achieve the above goal by redefining dp[i] to be the max profit out of 0 to the ith jobs,  not the max profit out of 0 to the ith jobs with the ith job scheduled.  The dynamic programming state definition in the O(N^2) solution forces us to check each smaller index in order to find the max profit that does not overlap the ith job. 

    state: dp[i]: max profit out of 0 to ith jobs
    dp[i] = Math.max(dp[i - 1], max profit out of 0 to ith jobs, including the ith job)

    O(N * log N) runtime

    class Solution {
        class Job {
            int start, end, profit;
            Job(int start, int end, int profit) {
                this.start = start;
                this.end = end;
                this.profit = profit;
            }
            int getEnd() {
                return end;
            }
        }
        public int jobScheduling(int[] startTime, int[] endTime, int[] profit) {
            int n = profit.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(Job::getEnd));
            
            //dp[i]: max profit out of 0 to ith jobs
            //dp[i] = Math.max(dp[i - 1], max profit out of 0 to ith jobs, including the ith job)
            int[] dp = new int[n];
            dp[0] = jobs[0].profit;
            
            for(int i = 1; i < n; i++) {
                int currProfit = jobs[i].profit;
                //find the max profit out of all 0 to i - 1 jobs that has no intersection with the current job.
                //A linear search causes TLE; since we already sorted jobs based on their end time and the dp
                //array is sorted in non-decreasing nature(always pick the max possible value). This means as long
                //as we find the largest j, j < i, that jobs[j].endTime <= jobs[i].startTime, we can just skip all
                //the rest jobs k with k < j, because dp[k] <= dp[j].
                int lastNonOverLapIdx = binarySearch(jobs, 0, i - 1, jobs[i].start);
                currProfit += lastNonOverLapIdx >= 0 ? dp[lastNonOverLapIdx] : 0;
                dp[i] = Math.max(currProfit, dp[i - 1]);
            }
            return dp[n - 1];
        }
        private int binarySearch(Job[] jobs, int l, int r, int t) {
            while(l < r - 1) {
                int mid = l + (r - l) / 2;
                if(jobs[mid].end <= t) {
                    l = mid;
                }
                else {
                    r = mid - 1;
                }
            }
            if(jobs[r].end <= t) {
                return r;
            }
            else if(jobs[l].end <= t) {
                return l;
            }
            return -1;
        }
    }
  • 相关阅读:
    用友U8存货分类通过DataTable生成EasyUI Tree JSON
    脚本加密与解密
    CKFinker 2.5.0.1 去demo标示
    C#压缩图片时保留原始的Exif信息
    Newtonsoft.Json转换强类型DataTable错误:Self referencing loop detected with type ......
    Access无法启动应用程序,工作组信息文件丢失,或是已被其他用户已独占方式打开
    C#获取邮件客户端保存的邮箱密码
    网站ASHX不执行故障
    水晶报表打印时出现:出现通信错误 将停止打印
    UILabel居上对齐居下对齐类别扩展
  • 原文地址:https://www.cnblogs.com/lz87/p/7288799.html
Copyright © 2011-2022 走看看