We have multiple employees, each with their own set of working intervals. We need to find the time slots where no employee is working, which are the gaps between the merged union of all working intervals.
Consider a single timeline with every employee's working hours marked on it. Wherever no interval covers the timeline, that uncovered stretch is free time for everyone. Those uncovered gaps are the answer.
Which employee an interval belongs to does not matter. We can collect all intervals from all employees, merge the overlapping ones, and the gaps between consecutive merged intervals are the common free time.
1 <= schedule.length, schedule[i].length <= 50. At most 50 employees, each with at most 50 intervals, so the total number of intervals N is at most 2,500. The input is small enough that even an O(N^2) approach would pass, but the natural solutions here are O(N log N) or better.0 <= schedule[i][j].start < schedule[i][j].end <= 10^8. Values reach 10^8, which fits comfortably in a 32-bit signed integer (max about 2.1 x 10^9), so subtracting two start times in a comparator cannot overflow. The time range itself is large, so iterating over individual time units is out of the question.Collect every working interval from every employee into one list, sort it by start time, then scan through it to find the gaps.
While scanning, track the farthest endpoint seen so far in prevEnd. If the next interval starts after prevEnd, the stretch between prevEnd and that start is uncovered, so it is free time. If the next interval starts at or before prevEnd, it overlaps the covered region, and we extend prevEnd to whichever endpoint is larger.
This is the merge-intervals pattern, except instead of outputting the merged blocks we output the gaps between them.
prevEnd to the end of the first interval.prevEnd, add the gap [prevEnd, current.start] to the result.prevEnd to be the maximum of prevEnd and the current interval's end.Loading animation...
Flattening and re-sorting discards the fact that each employee's intervals already arrive sorted. With K sorted lists, the next approach merges them in global order without a full sort.
Each employee's intervals are already sorted by start time, so we have K sorted lists of intervals. Instead of dumping them into one array and sorting, a min-heap pulls the next interval in global sorted order. Seed the heap with the first interval of each employee, then repeatedly extract the interval with the smallest start time, check it for a gap, and push that employee's next interval into the heap.
This holds at most K intervals in memory at once rather than all N, which is the win when K is much smaller than N.
The heap always hands back the smallest unextracted start time, so intervals come out in the same global order a full sort would produce. Because each employee's list is internally sorted, an interval can only enter the heap after its predecessor from the same employee has left, so no earlier-starting interval is ever missed. Processing in start order is what makes the running prevEnd a valid high-water mark for the gap check.
prevEnd.prevEnd, add the gap [prevEnd, start] to the result.prevEnd to max(prevEnd, current.end).Loading animation...
The next approach decomposes each interval into separate start and end events and sweeps through the timeline, which counts how many employees overlap at any moment rather than merging whole intervals.
Break each interval into two events: a "start working" event and a "stop working" event. Sort all events by time, then sweep through them tracking how many employees are currently working.
Whenever the active count drops to zero and later rises again, the span between those two moments is free for everyone.
This is the line sweep technique, which applies to interval problems generally, from meeting rooms to the skyline problem.
One ordering detail matters: when a start event and an end event share the same time, process the end event first. Otherwise an interval ending at t and another starting at t would briefly register a false drop to zero at t, producing a spurious zero-length gap. Sorting by (time, type) with type = -1 for end and +1 for start places ends before starts at equal times, so the count never dips between two intervals that touch.
[start, end], create two events: (start, +1) for "someone starts working" and (end, -1) for "someone stops working".-1) before start events (+1).Loading animation...