Employee Free Time solution and explanation
9 more videos on this problem
LeetCode 759. Employee Free TimeHappy Coding · 15:37 · 8K views
花花酱 LeetCode 759. Employee Free Time - 刷题找工作 EP 154Hua Hua · 10:54 · 5K views
Employee Free Time | LeetCode 759 (Hard)Destination FAANG · 10:42 · 3K views
LeetCode 759 | Employee Free Time | PriorityQueue | JavaSleepy Cracker · 6:33 · 2K views
LeetCode 759 Employee Free Timewellwellwell no · 5:50 · 2K views
FACEBOOK - Employee Free Time LeetCode -759Gilbert Zhuo · 10:51 · 1K views
759. Employee Free Time (Leetcode Hard)Programming Live with Larry · 16:10 · 890 views
LeetCode 759 Employee Free TimeAlgolab · 24:00 · 688 views
[LeetCode] 759. Employee Free Timebraxtonkin · 21:05 · 568 views
Employee Free Time - Priority Queues - PythonAI HMP · 16:21 · 511 views
The problem
We are given a list schedule of employees, which represents the working time for each employee.
Each employee has a list of non-overlapping Intervals, and these intervals are in sorted order.
Return the list of finite intervals representing common, positive-length free time for all employees, also in sorted order.
(Even though we are representing Intervals in the form [x, y], the objects inside are Intervals, not lists or arrays. For example, schedule[0][0].start = 1, schedule[0][0].end = 2, and schedule[0][0][0] is not defined). Also, we wouldn't include intervals like [5, 5] in our answer, as they have zero length.
Example 1:
Input: schedule = [[[1,2],[5,6]],[[1,3]],[[4,10]]] Output: [[3,4]] Explanation: There are a total of three employees, and all common free time intervals would be [-inf, 1], [3, 4], [10, inf]. We discard any intervals that contain inf as they aren't finite.
Example 2:
Input: schedule = [[[1,3],[6,7]],[[2,4]],[[2,5],[9,12]]] Output: [[5,6],[7,9]]
Constraints:
1 <= schedule.length , schedule[i].length <= 500 <= schedule[i].start < schedule[i].end <= 10^8
Approach overview
Problem Overview: Each employee has a sorted list of non-overlapping working intervals. The goal is to return all finite intervals where every employee is simultaneously free. In practice, you need to combine multiple schedules and detect the gaps between merged working intervals.
Approach 1: Brute Force Flatten + Sort (O(N log N) time, O(N) space)
Collect every interval from every employee into a single list. Sort the intervals by start time using a standard sorting step. Then iterate through the sorted intervals while maintaining the latest merged end time. If the next interval starts after the current end, that gap represents a block of shared free time. This approach works because once intervals are globally ordered, detecting gaps becomes a simple linear scan.
Approach 2: Interval Merging (O(N log N) time, O(N) space)
This is the most common implementation. Flatten all intervals, sort by start time, and merge overlapping intervals using the classic array-based interval merging pattern. Maintain a merged interval list and extend the current interval whenever overlaps occur. After merging, iterate through the merged list and return the gaps between consecutive intervals. The key insight: free time appears only between merged busy intervals shared across all employees.
Approach 3: K-Way Merge with Min Heap (O(N log K) time, O(K) space)
Instead of flattening everything, treat each employee schedule as a sorted stream and perform a k-way merge using a heap (priority queue). Push the first interval from each employee into a min-heap keyed by start time. Repeatedly pop the earliest interval and track the maximum end time seen so far. If the next interval starts after that end, you found a shared free slot. Then push the next interval from the same employee into the heap. This reduces sorting cost because the heap only manages K employees at once.
Recommended for interviews: The interval merging approach is typically expected. It shows you recognize the classic "merge intervals" pattern and can apply it after flattening schedules. Mentioning the heap-based k-way merge demonstrates deeper knowledge of multi-stream merging and improves scalability when many employees are involved. Starting with the brute-force flattening idea shows understanding, but the optimized merging or heap approach signals strong algorithmic reasoning.
Solution
We can merge all employees' working time intervals into a single list, then sort and merge the overlapping intervals. Finally, we traverse the merged interval list to find the free time periods between adjacent intervals.
The time complexity is O(mn log(mn)) and the space complexity is O(mn), where m is the number of employees and n is the number of working intervals per employee.
"""
# Definition for an Interval.
class Interval:
def __init__(self, start: int = None, end: int = None):
self.start = start
self.end = end
"""
class Solution:
def employeeFreeTime(self, schedule: "[[Interval]]") -> "[Interval]":
intervals = []
for e in schedule:
intervals.extend(e)
intervals.sort(key=lambda x: (x.start, x.end))
merged = [intervals[0]]
for x in intervals[1:]:
if merged[-1].end < x.start:
merged.append(x)
else:
merged[-1].end = max(merged[-1].end, x.end)
ans = []
for a, b in pairwise(merged):
ans.append(Interval(a.end, b.start))
return ans/*
// Definition for an Interval.
class Interval {
public int start;
public int end;
public Interval() {}
public Interval(int _start, int _end) {
start = _start;
end = _end;
}
};
*/
class Solution {
public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {
List<Interval> intervals = new ArrayList<>();
for (List<Interval> e : schedule) {
intervals.addAll(e);
}
intervals.sort((a, b) -> a.start == b.start ? a.end - b.end : a.start - b.start);
List<Interval> merged = new ArrayList<>();
merged.add(intervals.get(0));
for (int i = 1; i < intervals.size(); ++i) {
Interval last = merged.get(merged.size() - 1);
Interval cur = intervals.get(i);
if (last.end < cur.start) {
merged.add(cur);
} else {
last.end = Math.max(last.end, cur.end);
}
}
List<Interval> ans = new ArrayList<>();
for (int i = 1; i < merged.size(); ++i) {
Interval a = merged.get(i - 1);
Interval b = merged.get(i);
ans.add(new Interval(a.end, b.start));
}
return ans;
}
}/*
// Definition for an Interval.
class Interval {
public:
int start;
int end;
Interval() {}
Interval(int _start, int _end) {
start = _start;
end = _end;
}
};
*/
class Solution {
public:
vector<Interval> employeeFreeTime(vector<vector<Interval>> schedule) {
vector<Interval> intervals;
for (auto& e : schedule) {
intervals.insert(intervals.end(), e.begin(), e.end());
}
sort(intervals.begin(), intervals.end(), [](const Interval& a, const Interval& b) {
if (a.start == b.start) return a.end < b.end;
return a.start < b.start;
});
vector<Interval> merged;
merged.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); ++i) {
auto& last = merged.back();
auto& cur = intervals[i];
if (last.end < cur.start) {
merged.push_back(cur);
} else {
last.end = max(last.end, cur.end);
}
}
vector<Interval> ans;
for (int i = 1; i < merged.size(); ++i) {
auto& a = merged[i - 1];
auto& b = merged[i];
ans.emplace_back(a.end, b.start);
}
return ans;
}
};/**
* // Definition for an Interval.
* class Interval {
* start: number;
* end: number;
* constructor(start: number, end: number) {
* this.start = start;
* this.end = end;
* }
* }
*/
function employeeFreeTime(schedule: Interval[][]): Interval[] {
const intervals: Interval[] = [];
for (const e of schedule) {
intervals.push(...e);
}
intervals.sort((a, b) => (a.start === b.start ? a.end - b.end : a.start - b.start));
const merged: Interval[] = [intervals[0]];
for (let i = 1; i < intervals.length; ++i) {
const last = merged[merged.length - 1];
const cur = intervals[i];
if (last.end < cur.start) {
merged.push(cur);
} else {
last.end = Math.max(last.end, cur.end);
}
}
const ans: Interval[] = [];
for (let i = 1; i < merged.length; ++i) {
const a = merged[i - 1];
const b = merged[i];
ans.push(new Interval(a.end, b.start));
}
return ans;
}/**
* Definition for an Interval.
* type Interval struct {
* Start int
* End int
* }
*/
func employeeFreeTime(schedule [][]*Interval) []*Interval {
var intervals []*Interval
for _, e := range schedule {
intervals = append(intervals, e...)
}
sort.Slice(intervals, func(i, j int) bool {
if intervals[i].Start == intervals[j].Start {
return intervals[i].End < intervals[j].End
}
return intervals[i].Start < intervals[j].Start
})
merged := []*Interval{intervals[0]}
for _, cur := range intervals[1:] {
last := merged[len(merged)-1]
if last.End < cur.Start {
merged = append(merged, cur)
} else if cur.End > last.End {
last.End = cur.End
}
}
var ans []*Interval
for i := 1; i < len(merged); i++ {
a, b := merged[i-1], merged[i]
ans = append(ans, &Interval{Start: a.End, End: b.Start})
}
return ans
}Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Flatten + Sort | O(N log N) | O(N) | Simple implementation when total intervals are manageable |
| Interval Merging | O(N log N) | O(N) | General case and most common interview solution |
| K-Way Merge with Heap | O(N log K) | O(K) | Large number of intervals but relatively few employees |
Frequently asked questions
Is Employee Free Time easy or hard?
Employee Free Time is classified as a Hard problem because it combines multiple concepts: interval merging, handling multiple sorted lists, and detecting gaps between merged intervals. The core logic becomes manageable once you recognize it as a merge-intervals pattern.
Employee Free Time Python/Java solution
Python and Java implementations typically flatten all intervals into a list, sort by start time, and perform interval merging. Python uses list sorting and iteration, while Java often uses a List with Collections.sort and interval comparison logic.
How to solve Employee Free Time in O(n)?
Pure O(n) time is not possible unless the intervals are already globally sorted. If all intervals from every employee are pre-sorted by start time, you can scan them once and detect gaps between merged intervals in linear time. Otherwise, sorting or heap merging introduces a logarithmic factor.
What is the best approach for Employee Free Time?
The interval merging approach is the most common solution. Flatten all employee intervals, sort them by start time, merge overlapping intervals, then return the gaps between merged intervals. This runs in O(N log N) time and O(N) space, where N is the total number of intervals.
Is Employee Free Time asked at Google/Amazon/Meta?
Employee Free Time is a well-known interval problem and appears in interview prep sets used by companies like Google, Amazon, and Meta. It tests understanding of interval merging, sorting, and heap-based multi-list merging patterns.
What data structure is used in Employee Free Time?
The most common structures are arrays or lists for storing intervals and sorting them. An optimized solution may use a min heap (priority queue) to perform a k-way merge across employee schedules while tracking the earliest start times.
What is the time complexity of Employee Free Time?
The typical solution runs in O(N log N) time due to sorting all intervals before merging them. A heap-based k-way merge optimization can achieve O(N log K) time where K is the number of employees. Space complexity is usually O(N) for storing intervals or O(K) for the heap.
