253. Meeting Rooms II
Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],…] (si < ei), find the minimum number of conference rooms required.
Example 1:
Input: [[0, 30],[5, 10],[15, 20]]
Output: 2
Example 2:
Input: [[7,10],[2,4]]
Output: 1
方法0: brute force
方法1: hash
granndyang: https://www.cnblogs.com/grandyang/p/5244720.html
思路:
先来看使用 TreeMap 来做的,我们遍历时间区间,对于起始时间,映射值自增1,对于结束时间,映射值自减1,然后我们定义结果变量 res,和房间数 rooms,我们遍历 TreeMap,时间从小到大,房间数每次加上映射值,然后更新结果 res,遇到起始时间,映射是正数,则房间数会增加,如果一个时间是一个会议的结束时间,也是另一个会议的开始时间,则映射值先减后加仍为0,并不用分配新的房间,而结束时间的映射值为负数更不会增加房间数。
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
int minMeetingRooms(vector<Interval>& intervals) {
if (intervals.empty()) return 0;
map<int, int> rooms;
for (auto interval: intervals){
++rooms[interval.start];
--rooms[interval.end];
}
int result = 0, mx = 0;
for (auto c: rooms){
mx += c.second;
result = max(result, mx);
}
return result;
}
};
方法2: vector/set
basketwang: https://www.youtube.com/watch?v=0roQnDBC27o
思路:
这是这道题最简单的解法。核心在于,我们并不需要知道在每个时间点具体哪些会议结束了, 只需要知道结束和开始之间的相对顺序。举个栗子:s1, s2, s3, e1, s4, 或者s1, s2, s3, e2, s4, 或者s1, s2, s3, e3, s4, 此时都已经占用了2个会议室,而不管是谁结束了,s4都可以继承这个会议室而不开新的。而下次s5再想开会的时候,只需要和顺位下一个end比较,如果前面三个房间没有end,必须room++。那么如果一下结束了三个会议呢?比如s1, s2,s3, e1, s4, e2, e3, e4, s5,只要s5, s6, s7每次都晚于下一个结束时间,就不用新增房间,大不了可以空着。所以只有++没有–,把room当全球变量来用。
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
int minMeetingRooms(vector<vector<int>>& intervals) {
if (intervals.empty()) return 0;
vector<int> starts, ends;
for (auto v: intervals) {
starts.push_back(v[0]);
ends.push_back(v[1]);
}
sort(starts.begin(), starts.end());
sort(ends.begin(), ends.end());
int room = 1;
int j = 0;
for (int i = 1; i < intervals.size(); i++) {
if (starts[i] >= ends[j]) j++;
else {
room ++;
}
}
return room;
}
};
方法3: interval + heap
// greedy : always change the smallest end time;
// heap : min_heap
// sort : sort the intervals by start time O(nlogn)
int minMeetingRooms(vector<Interval>& intervals) {
sort(intervals.begin(), intervals.end(), [](Interval &i, Interval &j){return i.start < j.start;});
priority_queue<int, vector<int>, greater<int>> min_heap;
for(auto interval : intervals){
if(!min_heap.empty() && min_heap.top() <= interval.start) min_heap.pop();
min_heap.push(interval.end);
}
return min_heap.size();
}
方法4: sweep line + heap
class Solution {
public:
int minMeetingRooms(vector<vector<int>>& intervals) {
int n = intervals.size();
auto cmp = [](pair<int, bool> & a, pair<int, bool> & b) {
if (a.first == b.first) return a.second;
return a.first > b.first;
};
priority_queue<pair<int, bool>, vector<pair<int, bool>>, decltype(cmp)> events(cmp);
for (auto v: intervals) {
events.push(make_pair(v[0], true));
events.push(make_pair(v[1], false));
}
int count = 0, res = 0;
while (!events.empty()) {
auto top = events.top();
events.pop();
if (top.second) count++;
else count--;
res = max(res, count);
}
return res;
}
};
follow up:print出所有overlap的时间段,注意handle所有的corner case。举个栗子:如果[1,2] [2, 3], [1.5, 2.5],要输出[1.5, 2.5],而不是[1.5, 2], [2, 2.5]。这里如果sweep在相同时刻以end优先,会出现[1.5, 2], [2, 2.5]。但是如果start优先,在[1,2],[2,3]又会出现[2, 2]这样的输出,所以最优解法是在events里面combine事件的增减数量,比如2这一时刻对应的是0,不会对count发生任何影响,在两种情况下也就不会输出。count的增减都potentially误导输出。虽然用end优先的方式可以再过第二遍merge interval。
下面这个是在priority queue的阶段就collapse一下:可以进一步试试打印出interval。
//
class Solution {
public:
int minMeetingRooms(vector<vector<int>>& intervals) {
int res = 0;
unordered_map<int, int> hash;
for (auto v: intervals) {
hash[v[0]]++;
hash[v[1]]--;
}
auto cmp = [](pair<int, int> & a, pair<int, int> & b) {
return a.first > b.first;
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> pq(cmp);
for (auto item: hash) {
pq.push({item.first, item.second});
}
int room = 0;
while (!pq.empty()) {
auto top = pq.top();
pq.pop();
room += top.second;
res = max(res, room);
}
return res;
}
};
这个做法类似于merge interval, 把后面能排在一起的都消掉,公用一间。计数有多少条thread。
class Solution3 {
public:
int minMeetingRooms(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end());
int room = 0;
for (auto i = intervals.begin(); i != intervals.end(); i++) {
room++;
auto it = lower_bound(intervals.begin(), intervals.end(), vector<int>{(*i)[1], (*i)[1]});
while (it != intervals.end()) {
int e = (*it)[1];
intervals.erase(it);
it = lower_bound(intervals.begin(), intervals.end(), vector<int>{e, e});
}
}
return room;
}
};