LeetCode 253. 会议室 II
题目描述
题意分析
给定所有会议的开始和结束时间,安排足够多的会议室,使每场会议都能按原定时间进行;同一房间不能同时召开两场会议。返回需要的最少房间数,不要求返回具体分配方案。
一场会议结束的时刻,房间就能立刻供另一场会议使用,所以结束时间等于下一场开始时间不算冲突。会议时段本身固定,不能靠移动、拆分或取消会议减少房间。
解法:开始结束时间双指针
核心思路
[!blue]
同一时刻若有
r场会议进行,就至少需要r个房间,因此最大同时进行数是答案的下界。这个下界也足够:按时间处理会议,结束就释放房间,开始就使用一个空闲房间;只要房间总量达到历史最大同时进行数,每次开始时就一定有足够空间。计算同时进行数只关心“某时刻增加一场”或“减少一场”,不需要知道开始、结束属于哪个房间。把全部开始时间和结束时间分别排序,再用两个指针合并事件顺序,就能沿时间轴统计占用变化。
startIdx、endIdx分别表示已处理的开始、结束事件数,active = startIdx - endIdx表示当前占用数。下一个开始严格早于下一个结束时,先增加占用并更新峰值;否则先处理结束,释放一个房间。同时发生的结束事件必须先处理,才能让随后开始的会议复用房间。所有开始事件处理完后,只剩释放事件,占用数不可能再创新高,因此扫描可以结束,返回记录的峰值,而不是最后的
active。
解题步骤
- 没有会议时返回
0;否则将开始、结束时间分别存入两个数组并升序排序。- 初始化两个事件指针、当前占用
active和历史峰值answer为零。- 当前开始时间严格小于当前结束时间时,增加
active,更新answer,推进开始指针。- 其他情况先减少
active,推进结束指针;时间相等也走这个分支。- 全部开始事件处理完后,返回最大同时占用数
answer。
代码实现
class Solution {
public int minMeetingRooms(int[][] intervals) {
int n = intervals.length;
if (n == 0) {
return 0;
}
int[] starts = new int[n];
int[] ends = new int[n];
for (int i = 0; i < n; i++) {
starts[i] = intervals[i][0];
ends[i] = intervals[i][1];
}
Arrays.sort(starts);
Arrays.sort(ends);
int startIdx = 0;
int endIdx = 0;
int active = 0;
int answer = 0;
while (startIdx < n) {
// 开始与结束同刻时先释放房间,严格早于结束才新增占用。
if (starts[startIdx] < ends[endIdx]) {
active++;
answer = Math.max(answer, active);
startIdx++;
} else {
active--;
endIdx++;
}
}
return answer;
}
}
import "sort"
func minMeetingRooms(intervals [][]int) int {
n := len(intervals)
if n == 0 {
return 0
}
starts := make([]int, n)
ends := make([]int, n)
for i, interval := range intervals {
starts[i] = interval[0]
ends[i] = interval[1]
}
sort.Ints(starts)
sort.Ints(ends)
startIdx := 0
endIdx := 0
active := 0
answer := 0
for startIdx < n {
// 开始与结束同刻时先释放房间,严格早于结束才新增占用。
if starts[startIdx] < ends[endIdx] {
active++
if active > answer {
answer = active
}
startIdx++
} else {
active--
endIdx++
}
}
return answer
}
复杂度分析
- 时间复杂度:$O(n\log n)$,两个端点数组排序占主导;每个事件指针只向前移动,扫描为 $O(n)$。
- 空间复杂度:$O(n)$,创建两个长度为会议数的端点数组。
关键点总结
[!green]
- 最大同时进行数既是房间数的必要下界,也能通过及时复用房间达到。
- 拆开端点只丢掉会议身份,不丢失同时占用数所需要的事件信息。
- 相同时间先结束后开始,准确表达会议室可以立即复用的规则。
- 保存历史峰值,后续释放不会抹去此前需要过的房间数量。
易错点总结
[!yellow]
- 把开始事件的判断写成
<=,相同时间会先占用后释放,虚增房间数。- 端点数组没有分别排序,两个指针就不能代表下一件按时间发生的事件。
- 返回最后的
active,忽略了此前可能出现过更高的同时占用数。- 混淆事件计数与会议分配,认为开始端点和结束端点拆开就无法求解;数量只取决于累积增减。
- 空输入仍读取第一个结束时间会越界,已有的提前返回需要保留。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 252. 会议室 | 简单 | 只用一间房等价于全部区间无重叠,本题要求计算所有时刻的最大并发数。 |
| 732. 我的日程安排表 III | 困难 | 同样维护区间最大重叠数量,原题日程逐次加入,本题可离线排序全部事件。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!