【leetcode】1235. 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

解题思路:很容易看出应该用动态规划。假设dp[i]为第i个工作在所有选择的工作序列中排在最后一个时可以获得的最大利润,那么有dp[i] = max(dp[i],dp[j] + profit[i] )(i.startTime >= j.endTime)。但是这样时间复杂度是O(n^2),这无法被接受。继续寻找规律,对于dp[i]来说,我们要找的是所有endTime小于i.startTime的元素,所有我们可以按endTime升序排序,存储每个endTime可以获得的利润的最大值到一个列表中,这样的话,对于startTime来说,只要通过二分查找找到在endTime在列表中的位置,即可求得对应的最大值。

代码如下:

class Solution(object):
    def jobScheduling(self, startTime, endTime, profit):
        """
        :type startTime: List[int]
        :type endTime: List[int]
        :type profit: List[int]
        :rtype: int
        """
        import bisect
        item_list = []
        for (start,end,pro) in zip(startTime,endTime,profit):
            item_list.append((start,end,pro))
        def cmpf(v1,v2):
            if v1[1] != v2[1]:return v1[1] - v2[1]
            return v1[0] - v2[0]
        item_list.sort(cmp=cmpf)
        dp = [0] * len(item_list)
        dp[0] = item_list[0][2]

        end_time_order = []
        for i in range(len(item_list)):
            end_time_order.append(item_list[i][1])

        max_val_list = [dp[0]]
        max_val = dp[0]
        for i in range(1,len(item_list)):
            dp[i] = item_list[i][2]

            start = item_list[i][0]

            #left = bisect.bisect_left(end_time_order,start)
            right = bisect.bisect_right(end_time_order,start)
            if right == len(max_val_list) and end_time_order[right-1] <= start:
                dp[i] = max_val_list[-1] + item_list[i][2]
            elif right < len(max_val_list) and right > 0:
                dp[i] = max_val_list[right-1] + item_list[i][2]
            max_val = max(max_val,dp[i])
            max_val_list.append(max_val)
            #dp[i] = max(dp[i],dp[i-1])
        #print dp
        #print max_val_list
        return max(dp)
        

 

posted @ 2019-10-24 10:39  seyjs  阅读(551)  评论(0编辑  收藏  举报