Count Days Without Meetings
MedPrompt
You are given a positive integer days representing the total number of days an employee is available for work (starting from day 1). You are also given a 2D array meetings of size n where, meetings[i] = [start_i, end_i] represents the starting and ending days of meeting i (inclusive).
Return the count of days when the employee is available for work but no meetings are scheduled.
Note: The meetings may overlap.
Example 1:
Input: days = 10, meetings = [[5,7],[1,3],[9,10]]
Output: 2
Explanation:
There is no meeting scheduled on the 4th and 8th days.
Example 2:
Input: days = 5, meetings = [[2,4],[1,3]]
Output: 1
Explanation:
There is no meeting scheduled on the 5th day.
Example 3:
Input: days = 6, meetings = [[1,6]]
Output: 0
Explanation:
Meetings are scheduled for all working days.
Constraints:
1 <= days <= 1091 <= meetings.length <= 105meetings[i].length == 21 <= meetings[i][0] <= meetings[i][1] <= days
Approaches
2 approaches with complexity analysis and trade-offs.
This approach simulates the days and meetings directly. We use a boolean array, where each index represents a day. We iterate through all meetings and mark the corresponding days in the array as busy. Finally, we count the number of days that were never marked.
Algorithm
- Create a boolean array
hasMeetingof sizedays + 1, and initialize all its elements tofalse. - Iterate through each
meetingin the inputmeetingsarray. - For each
meeting = [start, end], loop fromi = starttoendand sethasMeeting[i] = true. - Initialize a counter
freeDaysto 0. - Loop from
i = 1todays. - If
hasMeeting[i]isfalse, it means the day is free, so incrementfreeDays. - After the loop, return
freeDays.
Walkthrough
The core idea is to maintain a status for each day from 1 to days. A boolean array isMeetingDay of size days + 1 is used for this purpose, where isMeetingDay[i] will be true if there's a meeting on day i, and false otherwise.
First, we initialize the entire array to false. Then, we iterate through each meeting interval [start, end] provided in the meetings array. For each interval, we run a nested loop from start to end and set isMeetingDay[j] = true for all j in this range. This process marks all days that are covered by at least one meeting.
After processing all the meetings, we perform a final scan through the boolean array from day 1 to days. We count how many indices i still have isMeetingDay[i] as false. This count represents the total number of days without any scheduled meetings.
public int countDays(int days, int[][] meetings) { if (days <= 0) { return 0; } boolean[] hasMeeting = new boolean[days + 1]; for (int[] meeting : meetings) { // Ensure meeting bounds are within the total days int start = Math.max(1, meeting[0]); int end = Math.min(days, meeting[1]); for (int i = start; i <= end; i++) { hasMeeting[i] = true; } } int freeDays = 0; for (int i = 1; i <= days; i++) { if (!hasMeeting[i]) { freeDays++; } } return freeDays;}Complexity
Time
O(N * L + D), where N is the number of meetings, L is the average length of a meeting, and D is the total number of `days`. In the worst case, a meeting can span all `days`, making the complexity O(N * D). Given the constraints, this will result in a Time Limit Exceeded (TLE) error.
Space
O(D), where D is the total number of `days`. We need a boolean array of size `days + 1`. Given the constraint `days <= 10^9`, this will cause a Memory Limit Exceeded (MLE) error.
Trade-offs
Pros
Simple to understand and implement.
Directly models the problem statement.
Cons
Extremely inefficient for large values of
days.Exceeds memory limits for
daysup to 10^9.Exceeds time limits for
daysup to 10^9.
A much more efficient approach is to treat this as an interval problem. The key insight is that we don't need to check every single day. Instead, we can find the total number of unique days covered by meetings and subtract this from the total days. To do this effectively, we first sort the meetings and then merge any overlapping or adjacent intervals into a set of disjoint intervals.
Algorithm
- Handle the edge case: if
meetingsis empty, returndays. - Sort the
meetingsarray based on the start times in ascending order. - Initialize
totalBusyDays = 0. - Initialize
mergedStartandmergedEndwith the start and end of the first meeting. - Iterate through the sorted
meetingsarray from the second meeting. - For the current
meeting = [start, end]:- If
startis less than or equal tomergedEnd, there is an overlap. Extend the current merged interval by updatingmergedEnd = max(mergedEnd, end). - If
startis greater thanmergedEnd, there is no overlap. The previous merged interval is complete. Calculate its duration (mergedEnd - mergedStart + 1) and add it tototalBusyDays. Then, start a new merged interval by settingmergedStart = startandmergedEnd = end.
- If
- After the loop finishes, add the duration of the last merged interval to
totalBusyDays. - The number of free days is
days - totalBusyDays. Return this value.
Walkthrough
The most efficient way to solve this problem is by focusing on the intervals themselves rather than individual days. The core idea is to merge overlapping intervals to find the total count of unique busy days, and then subtract this from the total number of days.
First, we sort the meetings array by their start day. This is a crucial step as it allows us to process meetings in chronological order and easily identify overlaps.
After sorting, we iterate through the meetings to merge them and calculate the total number of busy days. We start with the first meeting as our initial merged interval. Then, for each subsequent meeting, we check if it overlaps with our current merged interval.
- If it overlaps (i.e., its start time is before or at the end time of our merged interval), we extend our merged interval by updating its end time to the maximum of the two intervals' end times.
- If it does not overlap, the previous merged interval is complete. We calculate its length and add it to a running total of
busyDays. We then start a new merged interval with the current meeting.
After the loop, we add the length of the last merged interval to busyDays. The final answer is simply days - busyDays.
import java.util.Arrays; public int countDays(int days, int[][] meetings) { if (meetings.length == 0) { return days; } // Sort meetings by their start times Arrays.sort(meetings, (a, b) -> Integer.compare(a[0], b[0])); int busyDays = 0; int mergedStart = meetings[0][0]; int mergedEnd = meetings[0][1]; for (int i = 1; i < meetings.length; i++) { int[] currentMeeting = meetings[i]; if (currentMeeting[0] <= mergedEnd) { // Overlap or adjacent, merge the intervals by extending the end mergedEnd = Math.max(mergedEnd, currentMeeting[1]); } else { // No overlap, the previous merged interval is complete busyDays += (mergedEnd - mergedStart + 1); // Start a new merged interval mergedStart = currentMeeting[0]; mergedEnd = currentMeeting[1]; } } // Add the last merged interval to the count of busy days busyDays += (mergedEnd - mergedStart + 1); return days - busyDays;}Complexity
Time
O(N log N), where N is the number of meetings. The sorting step dominates the complexity. The subsequent single pass to merge intervals takes O(N) time.
Space
O(log N) or O(N), depending on the space used by the in-place sorting algorithm. For instance, Java's `Arrays.sort` for objects uses Timsort, which can take up to O(N) space in the worst case. No other significant auxiliary space is used.
Trade-offs
Pros
Highly efficient and scalable.
Correctly handles all cases, including overlapping and adjacent meetings.
Works for large values of
daysas its complexity is independent of the magnitude ofdays.
Cons
Requires sorting, which adds an O(N log N) time cost.
Slightly more complex to implement than the brute-force approach.
Solutions
Solution
class Solution {public int countDays(int days, int[][] meetings) { Arrays.sort(meetings, (a, b)->a[0] - b[0]); int ans = 0, last = 0; for (var e : meetings) { int st = e[0], ed = e[1]; if (last < st) { ans += st - last - 1; } last = Math.max(last, ed); } ans += days - last; return ans; }}class Solution {public: int countDays(int days, vector<vector<int>> &meetings) { sort(meetings.begin(), meetings.end()); int ans = 0, last = 0; for (auto &e : meetings) { int st = e[0], ed = e[1]; if (last < st) { ans += st - last - 1; } last = max(last, ed); } ans += days - last; return ans; }};class Solution: def countDays(self, days: int, meetings: List[List[int]]) -> int: meetings . sort() ans = last = 0 for st, ed in meetings: if last < st: ans += st - last - 1 last = max(last, ed) ans += days - last return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.