题目详情
给定一个会议时间安排的数组 intervals
,每个会议时间包括开始时间 start_i
和结束时间 end_i
(满足 start_i < end_i
)。为避免会议冲突,同时充分利用会议室资源,计算至少需要多少间会议室才能满足所有会议安排。
示例 1:
输入:intervals = [[0, 30], [5, 10], [15, 20]]
输出:2
解释:会议[5,10]和[0,30]时间冲突,需两个会议室;会议[15,20]可与 [5,10]共用会议室。
示例 2:
输入:intervals = [[7,10], [2,4]]
输出:1
解释:两会议时间无重叠,可共用会议室。
解题思路
核心思路:贪心算法 + 最小堆(优先队列)
- 排序会议:按开始时间升序排序,确保按时间顺序处理会议。
- 维护最小堆:存储当前正在使用会议室的结束时间,堆顶元素是最早结束的会议时间。
- 分配策略:
- 若当前会议的开始时间 ≥ 堆顶的结束时间:说明堆顶会议室已空闲,可复用(弹出堆顶)。
- 否则:需新开一间会议室。
- 无论是否复用,都将当前会议的结束时间加入堆中(代表占用会议室)。
- 结果:最终堆的大小即为所需的最少会议室数量。
时间复杂度:O(N log N)
- 排序耗时
O(N log N)
;堆的插入/弹出操作各O(log N)
,共N
次。
空间复杂度:O(N)
- 堆最坏存储
N
个元素。
代码实现(Java版)
class Solution {
public int minMeetingRooms(int[][] intervals) {
if (intervals == null || intervals.length == 0) {
return 0;
}
// 1. 按开始时间升序排序
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
// 2. 最小堆存储会议结束时间
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.offer(intervals[0][1]); // 初始化第一个会议
// 3. 遍历剩余会议
for (int i = 1; i < intervals.length; i++) {
int start = intervals[i][0];
int end = intervals[i][1];
// 若当前会议开始时,最早结束的会议室已空闲(堆顶结束时间 <= 当前开始时间)
if (start >= minHeap.peek()) {
minHeap.poll(); // 复用会议室
}
minHeap.offer(end); // 当前会议占用会议室(无论复用还是新增)
}
// 4. 堆大小即最少会议室数量
return minHeap.size();
}
}
代码说明
- 排序会议:
Arrays.sort(intervals, (a, b) -> a[0] - b[0])
确保按开始时间顺序处理会议。
- 最小堆的作用:
- 堆顶始终是最早结束的会议时间,通过比较
start >= minHeap.peek()
判断会议室是否可复用。
- 堆顶始终是最早结束的会议时间,通过比较
- 复用与新增逻辑:
- 若可复用(
start >= minHeap.peek()
),弹出堆顶(释放原会议室),加入新结束时间(重新占用)。 - 若不可复用,直接加入新结束时间(相当于新增会议室)。
- 若可复用(
- 结果正确性:
- 堆中元素数量表示同时进行的会议数量,即所需的最小会议室数。