Count Days Without Meetings
Number of days in [1, n] free of any meeting — merge intervals, count gaps.
4 min read
intervals
Problem#
You’re available days 1..days. Given a list of meeting intervals (1-indexed, inclusive), return the number of days with no meeting.
Examples#
days = 10, meetings = [[5,7],[1,3],[9,10]]→2(days 4 and 8)
Constraints#
1 <= days <= 10^9,1 <= meetings.length <= 10^5.
Approach#
Sort meetings by start, merge them on the fly. Track total busy days; answer is days - busy.
Solution#
class Solution {public: int countDays(int days, vector<vector<int>>& meetings) { sort(meetings.begin(), meetings.end()); long long busy = 0; int curStart = -1, curEnd = -1; for (auto& m : meetings) { if (m[0] > curEnd) { busy += curEnd - curStart + 1; curStart = m[0]; curEnd = m[1]; } else { curEnd = max(curEnd, m[1]); } } if (curStart >= 0) busy += curEnd - curStart + 1; return days - busy; }};import "sort"
func countDays(days int, meetings [][]int) int { sort.Slice(meetings, func(i, j int) bool { if meetings[i][0] != meetings[j][0] { return meetings[i][0] < meetings[j][0] } return meetings[i][1] < meetings[j][1] }) busy := 0 curStart, curEnd := -1, -1 for _, m := range meetings { if m[0] > curEnd { busy += curEnd - curStart + 1 curStart = m[0] curEnd = m[1] } else if m[1] > curEnd { curEnd = m[1] } } if curStart >= 0 { busy += curEnd - curStart + 1 } return days - busy}from typing import List
class Solution: def countDays(self, days: int, meetings: List[List[int]]) -> int: meetings.sort() busy = 0 cur_start, cur_end = -1, -1 for m in meetings: if m[0] > cur_end: busy += cur_end - cur_start + 1 cur_start = m[0] cur_end = m[1] elif m[1] > cur_end: cur_end = m[1] if cur_start >= 0: busy += cur_end - cur_start + 1 return days - busyfunction countDays(days, meetings) { meetings.sort((a, b) => a[0] - b[0] || a[1] - b[1]); let busy = 0; let curStart = -1, curEnd = -1; for (const m of meetings) { if (m[0] > curEnd) { busy += curEnd - curStart + 1; curStart = m[0]; curEnd = m[1]; } else if (m[1] > curEnd) { curEnd = m[1]; } } if (curStart >= 0) busy += curEnd - curStart + 1; return days - busy;}class Solution { public int countDays(int days, int[][] meetings) { Arrays.sort(meetings, (a, b) -> a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]); int busy = 0; int curStart = -1, curEnd = -1; for (int[] m : meetings) { if (m[0] > curEnd) { busy += curEnd - curStart + 1; curStart = m[0]; curEnd = m[1]; } else if (m[1] > curEnd) { curEnd = m[1]; } } if (curStart >= 0) busy += curEnd - curStart + 1; return days - busy; }}function countDays(days: number, meetings: number[][]): number { meetings.sort((a, b) => a[0] - b[0] || a[1] - b[1]); let busy = 0; let curStart = -1, curEnd = -1; for (const m of meetings) { if (m[0] > curEnd) { busy += curEnd - curStart + 1; curStart = m[0]; curEnd = m[1]; } else if (m[1] > curEnd) { curEnd = m[1]; } } if (curStart >= 0) busy += curEnd - curStart + 1; return days - busy;}Editorial#
Merging-as-we-go and summing the merged lengths avoids materializing the whole merged list. Tracking with a “current” interval plus a deferred commit handles the first iteration cleanly (we only commit when we encounter a non-overlapping next interval). The final commit picks up the last block.
Complexity#
- Time: O(m log m) for the sort.
- Space: O(1).
Concept revision#
Related#