Advertisement
hoangreal

Max Profit Non Overlap Intervals

Oct 20th, 2024 (edited)
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.05 KB | Source Code | 0 0
  1. """
  2. We have n jobs, where every job is scheduled to be done from startTime[i] to endTime[i], obtaining a profit of profit[i].
  3.  
  4. You're given the startTime, endTime and profit arrays, return the maximum profit you can take such that there are no two jobs in the subset with overlapping time range.
  5.  
  6. If you choose a job that ends at time X you will be able to start another job that starts at time X.
  7. """
  8.  
  9. class Solution:
  10.  
  11.     def solve(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int:
  12.         intervals = sorted(zip(startTime, endTime, profit), key = lambda item: item[0])
  13.         dp = [None for _ in range(len(intervals))]
  14.  
  15.         """ OLD
  16.        for i in range(len(dp)):
  17.            self.max_profit_from(i, dp, intervals = intervals)
  18.        return max(dp)
  19.        """
  20.        
  21.         start_interval_i = 0
  22.  
  23.         """ Recursive Solution
  24.        self.max_profit_from(start_interval_i, dp, intervals = intervals)
  25.        """
  26.         self.dp_solution(dp, intervals = intervals)
  27.  
  28.         ans = dp[start_interval_i - 0]
  29.         return ans
  30.  
  31.     def is_not_overlap(self, interval1: "tuple", interval2: "tuple"):
  32.         start1, end1 = interval1
  33.         start2, end2 = interval2
  34.         return end1 <= start2 or end2 <= start1
  35.  
  36.     def binary_search(self,
  37.         start_i, end_i, want_first_true: "bool",
  38.         *, decide_func, **kwargs): # -> index | None
  39.  
  40.         if start_i > end_i:
  41.             return None
  42.  
  43.         left_i = start_i; right_i = end_i; is_satisfy_problem = False
  44.         while left_i <= right_i:
  45.  
  46.             # [a, b] -> a; [a, b, c] -> b
  47.             mid_i = left_i + (right_i - left_i) // 2
  48.            
  49.             is_satisfy_problem = decide_func(mid_i, **kwargs)
  50.             if is_satisfy_problem == want_first_true:
  51.                 right_i = mid_i - 1
  52.             else:
  53.                 left_i = mid_i + 1
  54.        
  55.         final_i = left_i if want_first_true else left_i - 1
  56.         return final_i if start_i <= final_i <= end_i else None
  57.  
  58.     def dp_solution(self, dp, *, intervals):
  59.         """
  60.        Time Complexity: O(nlogn) -- n = len(intervals)
  61.        Space Complexity: O(n) -- n = len(intervals)
  62.        """
  63.         for interval_i in range(len(intervals) - 1, -1, -1):
  64.             dp_interval_i = interval_i
  65.  
  66.             ans = dp[dp_interval_i]
  67.             if ans is None:
  68.                 if interval_i == len(intervals) - 1: # Base
  69.                     ans = intervals[interval_i][2]
  70.                 else:
  71.                     next_non_overlap_index = self.binary_search(
  72.                         interval_i + 1, len(intervals) - 1,
  73.                         want_first_true = True,
  74.                         decide_func = lambda mid_i: self.is_not_overlap(
  75.                             intervals[mid_i][:2], intervals[interval_i][:2]
  76.                         )
  77.                     )                
  78.                     useIt_ans = intervals[interval_i][2]
  79.                     if next_non_overlap_index is not None:
  80.                         next_ans = dp[next_non_overlap_index]
  81.                         useIt_ans += next_ans
  82.  
  83.                     lostIt_ans = dp[interval_i + 1]
  84.                     ans = max(useIt_ans, lostIt_ans)                
  85.  
  86.             dp[dp_interval_i] = ans                    
  87.         return dp
  88.  
  89.     def max_profit_from(self, interval_i, dp, *, intervals: "list[interval]"):
  90.         dp_interval_i = interval_i
  91.  
  92.         ans = dp[dp_interval_i]
  93.         if ans is None:
  94.             if interval_i == len(intervals) - 1: # Base
  95.                 ans = intervals[interval_i][2]
  96.             else:            
  97.                 """ OLD
  98.                ans = -float('inf')
  99.                for next_interval_i in range(interval_i + 1, len(intervals)):
  100.                    if not self.is_not_overlap(intervals[interval_i][:2], intervals[next_interval_i][:2]):
  101.                        continue
  102.                    
  103.                    next_ans = self.max_profit_from(
  104.                        next_interval_i, dp,
  105.                        intervals = intervals
  106.                    )
  107.  
  108.                    ans = max(ans, next_ans + intervals[interval_i][2])
  109.                if ans == -float('inf'):
  110.                    ans = intervals[interval_i][2]
  111.                """
  112.  
  113.                 next_non_overlap_index = self.binary_search(
  114.                     interval_i + 1, len(intervals) - 1,
  115.                     want_first_true = True,
  116.                     decide_func = lambda mid_i: self.is_not_overlap(
  117.                         intervals[mid_i][:2], intervals[interval_i][:2]
  118.                     )
  119.                 )                
  120.                 useIt_ans = intervals[interval_i][2]
  121.                 if next_non_overlap_index is not None:
  122.                     next_ans = self.max_profit_from(next_non_overlap_index, dp, intervals = intervals)
  123.                     useIt_ans += next_ans
  124.  
  125.                 lostIt_ans = self.max_profit_from(interval_i + 1, dp, intervals = intervals)
  126.                 ans = max(useIt_ans, lostIt_ans)                
  127.  
  128.         dp[dp_interval_i] = ans
  129.         return ans
Tags: pinterest
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement