1229. Meeting Scheduler π
Problem Description
You are given two arrays slots1
and slots2
that represent the available time slots for two people, and an integer duration
representing the length of a meeting they need to schedule.
Each time slot is represented as an array [start, end]
, where start
and end
are inclusive boundaries (meaning the person is available from time start
to time end
, including both endpoints).
Your task is to find the earliest time slot where both people are available for at least duration
minutes. If such a common time slot exists, return an array [meetingStart, meetingEnd]
where the meeting would start at meetingStart
and end at meetingStart + duration
. If no such time slot exists, return an empty array []
.
Key constraints:
- Within each person's schedule, time slots don't overlap (they are non-intersecting)
- For any two slots
[start1, end1]
and[start2, end2]
of the same person, eitherstart1 > end2
orstart2 > end1
For example:
- If person 1 has slots
[[10, 50], [60, 120]]
- And person 2 has slots
[[0, 15], [45, 70]]
- With
duration = 8
- The earliest common available time would be
[45, 53]
(both are free from 45 to 50, which gives us at least 8 minutes)
The solution uses a two-pointer approach after sorting both arrays. It finds overlapping intervals between the two schedules and checks if the overlap is long enough to accommodate the required duration. The pointers advance based on which person's current slot ends earlier, ensuring we examine all possible overlapping intervals in chronological order.
Intuition
To find when both people can meet, we need to identify time periods where both are available simultaneously. This is essentially finding the intersection of two sets of time intervals.
The key insight is that we want the earliest possible meeting time. This naturally suggests processing the time slots in chronological order. By sorting both arrays first, we can examine potential meeting times from earliest to latest.
Once sorted, we can use two pointers to efficiently find overlapping intervals. For any pair of intervals (one from each person), the overlap exists from max(start1, start2)
to min(end1, end2)
. If this overlap has length β₯ duration
, we've found our answer.
Why two pointers? Consider what happens after checking two intervals:
- If person 1's interval ends before person 2's, there's no point checking person 1's current interval against any later intervals of person 2 (they'll start even later)
- We should move to person 1's next interval instead
- The same logic applies vice versa
This greedy approach works because:
- We're looking for the earliest valid time
- By processing intervals in sorted order, the first valid overlap we find is guaranteed to be the earliest
- We never need to backtrack because if intervals
i
andj
don't have sufficient overlap, and intervali
ends first, then intervali
won't have sufficient overlap with any interval afterj
either
The algorithm elegantly handles all cases: completely non-overlapping intervals, partial overlaps that are too short, and overlaps that satisfy our duration requirement.
Learn more about Two Pointers and Sorting patterns.
Solution Approach
The implementation follows a sorting + two pointers pattern to efficiently find the earliest common available time slot.
Step 1: Sort Both Arrays
slots1.sort() slots2.sort()
We sort both arrays by their start times (Python's default sorting for lists of lists sorts by the first element). This ensures we examine potential meeting times in chronological order.
Step 2: Initialize Two Pointers
m, n = len(slots1), len(slots2)
i = j = 0
We use pointer i
for slots1
and pointer j
for slots2
, starting both at index 0.
Step 3: Find Overlapping Intervals
while i < m and j < n:
start = max(slots1[i][0], slots2[j][0])
end = min(slots1[i][1], slots2[j][1])
For each pair of intervals, we calculate:
- The overlap starts at the later of the two start times:
max(slots1[i][0], slots2[j][0])
- The overlap ends at the earlier of the two end times:
min(slots1[i][1], slots2[j][1])
Step 4: Check if Overlap is Sufficient
if end - start >= duration: return [start, start + duration]
If the overlap duration (end - start
) is at least duration
minutes, we've found our answer. We return the interval [start, start + duration]
as the earliest valid meeting time.
Step 5: Advance the Appropriate Pointer
if slots1[i][1] < slots2[j][1]: i += 1 else: j += 1
If no valid meeting is found with the current pair:
- If person 1's interval ends earlier, move to their next interval (
i += 1
) - Otherwise, move to person 2's next interval (
j += 1
)
This ensures we don't miss any potential overlaps while avoiding unnecessary comparisons.
Step 6: Return Empty Array if No Solution
return []
If we exhaust either array without finding a valid meeting time, return an empty array.
Time Complexity: O(m log m + n log n)
for sorting, where m
and n
are the lengths of the two arrays. The two-pointer traversal is O(m + n)
.
Space Complexity: O(1)
if we don't count the space used for sorting (or O(log m + log n)
for the sorting stack space).
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to illustrate the solution approach:
Input:
slots1 = [[10, 50], [60, 120], [140, 210]]
slots2 = [[0, 15], [60, 70]]
duration = 8
Step 1: Sort both arrays (already sorted in this case)
slots1 = [[10, 50], [60, 120], [140, 210]]
slots2 = [[0, 15], [60, 70]]
Step 2: Initialize pointers
i = 0
(pointing to[10, 50]
in slots1)j = 0
(pointing to[0, 15]
in slots2)
Step 3: First iteration
- Current intervals:
[10, 50]
and[0, 15]
- Calculate overlap:
start = max(10, 0) = 10
end = min(50, 15) = 15
- Overlap duration:
15 - 10 = 5
(less than 8, not sufficient) - Since
slots1[0][1] = 50 > slots2[0][1] = 15
, advancej
to 1
Step 4: Second iteration
- Current intervals:
[10, 50]
and[60, 70]
- Calculate overlap:
start = max(10, 60) = 60
end = min(50, 70) = 50
- Since
60 > 50
, there's no overlap (invalid interval) - Since
slots1[0][1] = 50 < slots2[1][1] = 70
, advancei
to 1
Step 5: Third iteration
- Current intervals:
[60, 120]
and[60, 70]
- Calculate overlap:
start = max(60, 60) = 60
end = min(120, 70) = 70
- Overlap duration:
70 - 60 = 10
(greater than 8, sufficient!) - Return
[60, 60 + 8] = [60, 68]
Result: [60, 68]
- Both people are available from time 60 to 70, so they can meet from 60 to 68 (8 minutes).
This example demonstrates how the algorithm:
- Examines intervals in chronological order
- Calculates overlaps between pairs of intervals
- Advances the pointer whose interval ends earlier
- Returns immediately upon finding the first valid meeting time
Solution Implementation
1class Solution:
2 def minAvailableDuration(
3 self, slots1: List[List[int]], slots2: List[List[int]], duration: int
4 ) -> List[int]:
5 """
6 Find the earliest time slot that both people are available for a meeting of given duration.
7
8 Args:
9 slots1: List of available time slots for person 1, where each slot is [start, end]
10 slots2: List of available time slots for person 2, where each slot is [start, end]
11 duration: Required duration for the meeting
12
13 Returns:
14 List containing [start, end] of the earliest common available slot,
15 or empty list if no common slot exists
16 """
17 # Sort both slot lists by start time to process them chronologically
18 slots1.sort()
19 slots2.sort()
20
21 # Get the number of slots for each person
22 num_slots1, num_slots2 = len(slots1), len(slots2)
23
24 # Initialize two pointers to traverse both slot lists
25 pointer1 = pointer2 = 0
26
27 # Use two-pointer technique to find overlapping slots
28 while pointer1 < num_slots1 and pointer2 < num_slots2:
29 # Calculate the overlap between current slots
30 # The overlap starts at the later of the two start times
31 overlap_start = max(slots1[pointer1][0], slots2[pointer2][0])
32 # The overlap ends at the earlier of the two end times
33 overlap_end = min(slots1[pointer1][1], slots2[pointer2][1])
34
35 # Check if the overlap duration is sufficient for the meeting
36 if overlap_end - overlap_start >= duration:
37 # Return the earliest possible meeting slot
38 return [overlap_start, overlap_start + duration]
39
40 # Move the pointer for the slot that ends earlier
41 # This ensures we don't miss any potential overlaps
42 if slots1[pointer1][1] < slots2[pointer2][1]:
43 pointer1 += 1
44 else:
45 pointer2 += 1
46
47 # No common slot with sufficient duration was found
48 return []
49
1class Solution {
2 public List<Integer> minAvailableDuration(int[][] slots1, int[][] slots2, int duration) {
3 // Sort both slot arrays by start time in ascending order
4 Arrays.sort(slots1, (a, b) -> a[0] - b[0]);
5 Arrays.sort(slots2, (a, b) -> a[0] - b[0]);
6
7 // Get the lengths of both slot arrays
8 int slots1Length = slots1.length;
9 int slots2Length = slots2.length;
10
11 // Initialize two pointers for traversing both arrays
12 int pointer1 = 0;
13 int pointer2 = 0;
14
15 // Use two pointers to find the earliest common available slot
16 while (pointer1 < slots1Length && pointer2 < slots2Length) {
17 // Calculate the overlap interval between current slots
18 // The overlap starts at the later of the two start times
19 int overlapStart = Math.max(slots1[pointer1][0], slots2[pointer2][0]);
20 // The overlap ends at the earlier of the two end times
21 int overlapEnd = Math.min(slots1[pointer1][1], slots2[pointer2][1]);
22
23 // Check if the overlap duration is sufficient for the meeting
24 if (overlapEnd - overlapStart >= duration) {
25 // Found a valid slot, return the earliest possible meeting time
26 return Arrays.asList(overlapStart, overlapStart + duration);
27 }
28
29 // Move the pointer of the slot that ends earlier
30 // This ensures we don't miss any potential overlaps
31 if (slots1[pointer1][1] < slots2[pointer2][1]) {
32 pointer1++;
33 } else {
34 pointer2++;
35 }
36 }
37
38 // No common available slot found that meets the duration requirement
39 return Collections.emptyList();
40 }
41}
42
1class Solution {
2public:
3 vector<int> minAvailableDuration(vector<vector<int>>& slots1, vector<vector<int>>& slots2, int duration) {
4 // Sort both slot arrays by start time to process them in chronological order
5 sort(slots1.begin(), slots1.end());
6 sort(slots2.begin(), slots2.end());
7
8 // Get the size of both slot arrays
9 int slots1Size = slots1.size();
10 int slots2Size = slots2.size();
11
12 // Use two pointers to traverse both slot arrays
13 int pointer1 = 0;
14 int pointer2 = 0;
15
16 // Find the earliest common available time slot
17 while (pointer1 < slots1Size && pointer2 < slots2Size) {
18 // Calculate the overlapping interval between current slots
19 // The overlap starts at the later of the two start times
20 int overlapStart = max(slots1[pointer1][0], slots2[pointer2][0]);
21 // The overlap ends at the earlier of the two end times
22 int overlapEnd = min(slots1[pointer1][1], slots2[pointer2][1]);
23
24 // Check if the overlapping interval is long enough for the meeting
25 if (overlapEnd - overlapStart >= duration) {
26 // Return the earliest valid meeting time slot
27 return {overlapStart, overlapStart + duration};
28 }
29
30 // Move the pointer pointing to the slot that ends earlier
31 // This ensures we don't miss any potential overlaps
32 if (slots1[pointer1][1] < slots2[pointer2][1]) {
33 ++pointer1;
34 } else {
35 ++pointer2;
36 }
37 }
38
39 // No valid common time slot found
40 return {};
41 }
42};
43
1/**
2 * Finds the earliest time slot that works for both people with the given duration
3 * @param slots1 - Available time slots for person 1, each slot is [start, end]
4 * @param slots2 - Available time slots for person 2, each slot is [start, end]
5 * @param duration - Required duration for the meeting
6 * @returns The earliest available time slot [start, end] or empty array if none found
7 */
8function minAvailableDuration(slots1: number[][], slots2: number[][], duration: number): number[] {
9 // Sort both slot arrays by start time to process them in chronological order
10 slots1.sort((a, b) => a[0] - b[0]);
11 slots2.sort((a, b) => a[0] - b[0]);
12
13 // Get the lengths of both slot arrays
14 const person1SlotCount: number = slots1.length;
15 const person2SlotCount: number = slots2.length;
16
17 // Initialize pointers for both slot arrays
18 let person1Index: number = 0;
19 let person2Index: number = 0;
20
21 // Use two pointers to find overlapping slots
22 while (person1Index < person1SlotCount && person2Index < person2SlotCount) {
23 // Extract current slot boundaries for both persons
24 const [person1Start, person1End] = slots1[person1Index];
25 const [person2Start, person2End] = slots2[person2Index];
26
27 // Calculate the overlapping window between current slots
28 const overlapStart: number = Math.max(person1Start, person2Start);
29 const overlapEnd: number = Math.min(person1End, person2End);
30
31 // Check if the overlapping window can accommodate the required duration
32 if (overlapEnd - overlapStart >= duration) {
33 // Return the earliest possible meeting slot
34 return [overlapStart, overlapStart + duration];
35 }
36
37 // Move the pointer for the slot that ends earlier
38 if (person1End < person2End) {
39 person1Index++;
40 } else {
41 person2Index++;
42 }
43 }
44
45 // No valid meeting slot found
46 return [];
47}
48
Time and Space Complexity
Time Complexity: O(m Γ log m + n Γ log n)
The time complexity is dominated by the sorting operations:
- Sorting
slots1
takesO(m Γ log m)
time wherem
is the length ofslots1
- Sorting
slots2
takesO(n Γ log n)
time wheren
is the length ofslots2
- The while loop performs a two-pointer traversal through both sorted arrays, which takes
O(m + n)
time in the worst case
Therefore, the overall time complexity is O(m Γ log m + n Γ log n + m + n)
, which simplifies to O(m Γ log m + n Γ log n)
since the sorting operations dominate.
Space Complexity: O(log m + log n)
The space complexity comes from the sorting operations:
- Python's built-in
sort()
method uses Timsort algorithm, which requiresO(log m)
space for sortingslots1
in the worst case - Similarly, sorting
slots2
requiresO(log n)
space - The remaining variables (
i
,j
,start
,end
) use constantO(1)
space
Therefore, the total space complexity is O(log m + log n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to Sort the Input Arrays
One of the most common mistakes is assuming the input arrays are already sorted and skipping the sorting step. The problem statement doesn't guarantee that slots are given in chronological order.
Incorrect Code:
def minAvailableDuration(self, slots1, slots2, duration):
# WRONG: Directly using arrays without sorting
i = j = 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])
# ... rest of logic
Why it fails: Without sorting, you might miss the earliest valid slot. For example:
slots1 = [[50, 60], [10, 20]]
slots2 = [[15, 25], [55, 65]]
duration = 5
- Without sorting, you'd check [50,60] with [15,25] first and miss the earlier valid overlap at [15,20]
Solution: Always sort both arrays at the beginning:
slots1.sort() slots2.sort()
2. Incorrect Overlap Calculation
Another pitfall is incorrectly calculating whether two intervals overlap or the duration of their overlap.
Incorrect Code:
# WRONG: Using subtraction in wrong order if slots1[i][1] - slots2[j][0] >= duration: return [slots2[j][0], slots2[j][0] + duration]
Why it fails: This doesn't correctly check if both people are available. The overlap must consider both intervals' constraints.
Solution: Calculate overlap correctly:
start = max(slots1[i][0], slots2[j][0]) # Later start time
end = min(slots1[i][1], slots2[j][1]) # Earlier end time
if end - start >= duration: # Check if overlap is sufficient
return [start, start + duration]
3. Wrong Pointer Advancement Logic
A subtle mistake is advancing the wrong pointer or advancing both pointers simultaneously.
Incorrect Code:
# WRONG: Always advancing both pointers if end - start >= duration: return [start, start + duration] i += 1 j += 1
Why it fails: This skips potential valid overlaps. If slot1[0] = [10,20] and slot2[0] = [15,30], after checking them, we should only advance pointer for slots1 (since it ends first), not both.
Solution: Advance only the pointer whose interval ends earlier:
if slots1[i][1] < slots2[j][1]: i += 1 else: j += 1
4. Edge Case: Zero or Negative Overlap
Not handling cases where intervals don't overlap at all (when end < start
).
Incorrect Code:
start = max(slots1[i][0], slots2[j][0])
end = min(slots1[i][1], slots2[j][1])
# WRONG: Not checking if there's actual overlap
if end - start >= duration: # This could be negative!
return [start, start + duration]
Why it fails: When intervals don't overlap, end < start
, making end - start
negative. While the condition would still fail (negative < positive duration), it's better to be explicit.
Solution: You can add an explicit check or rely on the mathematical property:
start = max(slots1[i][0], slots2[j][0])
end = min(slots1[i][1], slots2[j][1])
# The condition naturally handles non-overlapping cases
if end - start >= duration: # When end < start, this is always false
return [start, start + duration]
5. Returning Wrong Meeting End Time
Returning [start, end]
instead of [start, start + duration]
.
Incorrect Code:
if end - start >= duration: # WRONG: Using the overlap end instead of start + duration return [start, end]
Why it fails: The meeting should be exactly duration
minutes long, not the entire overlap period.
Solution: Return the meeting slot with exact duration:
return [start, start + duration]
How would you design a stack which has a function min
that returns the minimum element in the stack, in addition to push
and pop
? All push
, pop
, min
should have running time O(1)
.
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Donβt Miss This!