Two Best Non-Overlapping Events

medium sorting binary search suffix maximum

Problem

You are given events where events[i] = [start, end, value]. The start and end times are inclusive, so two events overlap if one starts at or before the other ends. Choose at most two non-overlapping events to attend so that the sum of their values is maximized, and return that maximum sum. An event chosen after one ending at time t must start at t + 1 or later.

Inputevents = [[1,3,2],[4,5,2],[2,4,3]]
Output4
Attend [1,3,2] then [4,5,2] (they don't overlap) for 2 + 2 = 4.
Inputevents = [[1,5,3],[1,5,1],[6,6,5]]
Output8
Attend [1,5,3] then [6,6,5] for 3 + 5 = 8.

def max_two_events(events):
    events.sort(key=lambda e: e[0])         # sort by start time
    n = len(events)
    suffix = [0] * (n + 1)                   # suffix[i] = max value in events[i:]
    for i in range(n - 1, -1, -1):
        suffix[i] = max(suffix[i + 1], events[i][2])
    best = 0
    for s, e, v in events:
        lo, hi = 0, n                        # find first start > e
        while lo < hi:
            mid = (lo + hi) // 2
            if events[mid][0] > e:
                hi = mid
            else:
                lo = mid + 1
        best = max(best, v + suffix[lo])
    return best
function maxTwoEvents(events) {
  events.sort((a, b) => a[0] - b[0]);        // sort by start time
  const n = events.length;
  const suffix = new Array(n + 1).fill(0);   // suffix[i] = max value in events[i:]
  for (let i = n - 1; i >= 0; i--) {
    suffix[i] = Math.max(suffix[i + 1], events[i][2]);
  }
  let best = 0;
  for (const [s, e, v] of events) {
    let lo = 0, hi = n;                       // find first start > e
    while (lo < hi) {
      const mid = (lo + hi) >> 1;
      if (events[mid][0] > e) hi = mid;
      else lo = mid + 1;
    }
    best = Math.max(best, v + suffix[lo]);
  }
  return best;
}
int maxTwoEvents(int[][] events) {
    Arrays.sort(events, (a, b) -> a[0] - b[0]);   // sort by start time
    int n = events.length;
    int[] suffix = new int[n + 1];                // suffix[i] = max value in events[i:]
    for (int i = n - 1; i >= 0; i--)
        suffix[i] = Math.max(suffix[i + 1], events[i][2]);
    int best = 0;
    for (int[] ev : events) {
        int e = ev[1], v = ev[2];
        int lo = 0, hi = n;                       // find first start > e
        while (lo < hi) {
            int mid = (lo + hi) >>> 1;
            if (events[mid][0] > e) hi = mid;
            else lo = mid + 1;
        }
        best = Math.max(best, v + suffix[lo]);
    }
    return best;
}
int maxTwoEvents(vector<vector<int>>& events) {
    sort(events.begin(), events.end());           // sort by start time
    int n = events.size();
    vector<int> suffix(n + 1, 0);                  // suffix[i] = max value in events[i:]
    for (int i = n - 1; i >= 0; i--)
        suffix[i] = max(suffix[i + 1], events[i][2]);
    int best = 0;
    for (auto& ev : events) {
        int e = ev[1], v = ev[2];
        int lo = 0, hi = n;                        // find first start > e
        while (lo < hi) {
            int mid = (lo + hi) / 2;
            if (events[mid][0] > e) hi = mid;
            else lo = mid + 1;
        }
        best = max(best, v + suffix[lo]);
    }
    return best;
}
Time: O(n log n) Space: O(n)