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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值