The Meeting Scheduler problem asks you to find the earliest time slot that works for both people to have a meeting of a given duration, given each person's available time slots.
You are given two lists, slots1
and slots2
, where each element is a list of two integers [start, end]
representing an available time slot in minutes. You are also given an integer duration
representing the length of the meeting in minutes.
[start, end)
[start, start + duration]
that is available in both slots1
and slots2
.[]
.
At first glance, it seems like you could compare every possible pair of slots from slots1
and slots2
to check if they overlap for at least duration
minutes. However, this brute-force approach would be slow if there are many slots.
To optimize, notice that we only care about overlapping intervals that are at least as long as duration
. If we sort both lists by start time, we can efficiently walk through both lists (like merging two sorted lists), always advancing the slot that ends earlier. This way, we never revisit unnecessary comparisons, and we always check for the earliest possible overlap.
The key insight is to treat the problem like a two-pointer merge, focusing only on overlaps and moving forward as soon as a slot can't possibly help.
duration
in both slots1
and slots2
, since they can't possibly fit the meeting.slots1
and slots2
by their start times. This allows us to efficiently scan for overlaps.i
for slots1
and j
for slots2
. At each step, compare slots1[i]
and slots2[j]
:
max(start1, start2)
to min(end1, end2)
.duration
, return [overlap_start, overlap_start + duration]
.This approach is efficient because each slot is only considered once, and we avoid unnecessary comparisons.
Suppose slots1 = [[10, 50], [60, 120], [140, 210]]
, slots2 = [[0, 15], [60, 70]]
, and duration = 8
.
[10, 50]
(from slots1
) and [0, 15]
(from slots2
):
10
to 15
(5 minutes), which is less than 8.slots2
pointer, since [0, 15]
ends earlier.[10, 50]
and [60, 70]
:
60
to 50
, which is negative (no overlap).slots1
pointer, since [10, 50]
ends earlier.[60, 120]
and [60, 70]
:
60
to 70
(10 minutes), which is at least 8.[60, 68]
as the earliest slot.class Solution:
def minAvailableDuration(self, slots1, slots2, duration):
# Filter out slots shorter than duration
slots1 = [s for s in slots1 if s[1] - s[0] >= duration]
slots2 = [s for s in slots2 if s[1] - s[0] >= duration]
# Sort both lists by start time
slots1.sort()
slots2.sort()
i, j = 0, 0
while i < len(slots1) and j < len(slots2):
start = max(slots1[i][0], slots2[j][0])
end = min(slots1[i][1], slots2[j][1])
if end - start >= duration:
return [start, start + duration]
if slots1[i][1] < slots2[j][1]:
i += 1
else:
j += 1
return []
class Solution {
public:
vector<int> minAvailableDuration(vector<vector<int>>& slots1, vector<vector<int>>& slots2, int duration) {
vector<vector<int>> s1, s2;
for (auto& s : slots1)
if (s[1] - s[0] >= duration) s1.push_back(s);
for (auto& s : slots2)
if (s[1] - s[0] >= duration) s2.push_back(s);
sort(s1.begin(), s1.end());
sort(s2.begin(), s2.end());
int i = 0, j = 0;
while (i < s1.size() && j < s2.size()) {
int start = max(s1[i][0], s2[j][0]);
int end = min(s1[i][1], s2[j][1]);
if (end - start >= duration)
return {start, start + duration};
if (s1[i][1] < s2[j][1]) ++i;
else ++j;
}
return {};
}
};
class Solution {
public List<Integer> minAvailableDuration(int[][] slots1, int[][] slots2, int duration) {
List<int[]> s1 = new ArrayList<>();
List<int[]> s2 = new ArrayList<>();
for (int[] s : slots1)
if (s[1] - s[0] >= duration) s1.add(s);
for (int[] s : slots2)
if (s[1] - s[0] >= duration) s2.add(s);
s1.sort((a, b) -> a[0] - b[0]);
s2.sort((a, b) -> a[0] - b[0]);
int i = 0, j = 0;
while (i < s1.size() && j < s2.size()) {
int start = Math.max(s1.get(i)[0], s2.get(j)[0]);
int end = Math.min(s1.get(i)[1], s2.get(j)[1]);
if (end - start >= duration)
return Arrays.asList(start, start + duration);
if (s1.get(i)[1] < s2.get(j)[1]) i++;
else j++;
}
return new ArrayList<>();
}
}
var minAvailableDuration = function(slots1, slots2, duration) {
slots1 = slots1.filter(s => s[1] - s[0] >= duration);
slots2 = slots2.filter(s => s[1] - s[0] >= duration);
slots1.sort((a, b) => a[0] - b[0]);
slots2.sort((a, b) => a[0] - b[0]);
let i = 0, j = 0;
while (i < slots1.length && j < slots2.length) {
let start = Math.max(slots1[i][0], slots2[j][0]);
let end = Math.min(slots1[i][1], slots2[j][1]);
if (end - start >= duration)
return [start, start + duration];
if (slots1[i][1] < slots2[j][1]) i++;
else j++;
}
return [];
};
slots1
, compare to every slot in slots2
: O(N * M) time, where N and M are the lengths of the input lists.The Meeting Scheduler problem is a classic interval overlap challenge. By filtering, sorting, and using a two-pointer technique, we efficiently find the earliest overlapping slot of sufficient duration. This approach avoids unnecessary comparisons and leverages sorting for optimal performance. The key insight is to always advance the pointer with the earlier end time, ensuring we never miss a potential overlap. This makes the solution both elegant and efficient.