写在前面:
今天我们来看的题目是 Meeting Room 进阶版 Meeting Room II。推荐没有做过 Leetcode 的麻油们从 Meeting Room I 先开始,这样可以更好的思考 Meeting Room 场景下的思路
Meeting Room I 题目地址:https://leetcode.com/problems/meeting-rooms/description/https://leetcode.com/problems/meeting-rooms/description/
这道题目看起来是一个合并区间相关的问题,但在对 Meeting Room 这个场景的巧妙思考下,我们可以利用更高效的数据结构 Minheap 来解决这个问题。我们来一起看看吧!
题目介绍:
题目信息:
- 题目地址:https://leetcode.com/problems/meeting-rooms-ii/description/
- 题目类型:Array,PriorityQueue
- 题目难度:Medium
- 题目来源:Google 高频面试真题
题目问题:
- 给定一组数组,每个元素是一个 长度为 2 的固定数组,代表一个 Meeting 的开始和结束时间
- 每一个 Meeting Room 只能容纳一个 Meeting 同时进行
- 问如果需要将所有会议全部安排,最少需要多少个 Meeting Rooms
- 例子:
- [[1, 30], [5, 10], [30, 50]]
- 代表第一会议从单位 10 开始,第二个从单位5 开始,etc
- [1, 30] 和 [5, 10] 存在重复区间,则需要两个不同的 Meeting Room 才能安排
- [1, 30] 和 [30, 50] 之间不存在重复区间,可以在相同的 Meeting Room 进行
题目想法:
Meeting Room 场景思考:
- 对于 Meeting 是否有 Conflict,我们只需要看同一个 room 前一个 Meeting 的结束时间和后一个 Meeting 的开始时间即可
- 因为时间是有序的,所以我们在 schedule 的时候最好也将我们的 Meeting 发生时间进行正向排序,更契合我们真实的场景
- 对于已经 Schedule 的 Meeting,我们只 care 他们的 endTime 就行。而在所有的 Meeting Room 当中,我们只需要和最早结束的 endTime 进行对比就行。
- 因为如果这个 最早的 Meeting 已经结束,则我们直接 schedule 到这个位置
- 如果这个最早的 Meeting 没结束,则我们肯定需要一个新的 Meeting room 去 schedule 当前 meeting
- 我们之前的排序保证了我们每一次新 schedule 的 meeting 都是最早开始的,意味着我们每次都在尝试找到最优解 - 让每一个 room 内的 meeting 间隔最短,可容纳的 Meeting Room 越多
- 对于已经 Schedule 的 Meeting Room,我们可以针对他们的 endTime 用 minheap 进行排序,每次只需要和最上面的比对就可以
- 如果比最早结束的 Meeting 开始晚,则我们可以在相同房间安排,反之需要新房间
MinHeap 在场景下的使用:
对于 Minheap,我们每次比较当前 Meeting 的开始时间和 Minheap head 的结束时间:
- 如果可以 schedule,则 pop 掉头部结束时间,将当前 Meeting 的结束时间重新放进 Minheap,这就可以理解为使用了同一 Meeting Room
- 如果不可以schedule,则直接将当前 meeting 的结束时间放进 Minheap,这可以理解为需要一个新的 Meeting Room
- 最后整个 minHeap 的长度代表了需要的 Meeting Room 最小总数
题目解法:
- 如果 interval 长度为 1, 只有一个 meeting,直接 return 1
- 按照每个数组第一位(start time) 对整个数组进行排序
- 定义 Minheap,先放入第一个 Meeting 的 endTime
- 遍历所有 Meeting interval:
- 将当前 interval 的 start time 与 Minheap.top,也就是最早的 endtime 做比较
- 如果比最早的 endtime 结束的晚
- 将 top 从 Minheap 中剔除
- 将 当前 meeting 的 endtime 加入 Minheap 中
- else:
- 将当前 meeting 的 endtime 加入 Minheap 中
- 返回 priority queue 最终的长度
- Tip: 在只有 Maxheap 的语言中(如 C++),如果要使用 minheap,可以将所有元素值 * (-1)
题目代码:
class Solution {
public:
int minMeetingRooms(vector<vector<int>>& intervals) {
if(intervals.size() == 1) return 1;
//sort the meeting by start time
sort(intervals.begin(), intervals.end());
//initiate the room storage, each room stores the end time as min-heap
//if the smallest endtime cannot satisfied, we cannot proceed in this room.
priority_queue<int> roomsEndings;
roomsEndings.push(intervals[0][1] * (-1)); //only store the end-time as minheap
//for every meeting, check if we can fit in ended room
for(int i = 1; i < intervals.size(); i++){
//we can fit in, then update the room's ending time with the current one
if(intervals[i][0] >= roomsEndings.top() * (-1)){
roomsEndings.pop();
}
roomsEndings.push(intervals[i][1] * (-1));
}
return roomsEndings.size();
}
};
1. Runtime: O(nlogn) + O(n * logn) = O(nlogn)
2. Space: O(n)