【算法题解】leetcode 253 会议室II (贪心+堆)

leetcode 253 会议室II

题目描述

There are n meetings, and the start time and end time of i-th meeting are s i s_i si and e i e_i ei. Please design a greedy algorithm to find the minimum number of meeting rooms required to arrange all meetings.

给定一个会议时间安排的数组,每个会议时间都会包括开始和结束的时间 [[s1,e1],[s2,e2],…] (si < ei), 为避免会议冲突,同时要考虑充分利用会议室资源,请你计算至少需要多少间会议室,才能满足这些会议安排。

Input: [ [0, 20], [15, 20], [20, 23], [25, 30], [15, 25] ]
Output: 3

  • 算法标签
    • 贪心

错误的尝试

  • 这题有一个类似的题目是安排不冲突的最多的会议,那题的思路是对结束时间从早到晚排序,然后看到这个题目就思维定式了,啪的一下,很快啊就错了
  • 给一个反例
    • image-20230103123339022
    • 这种情况最少数量是2个,1和2复用一间会议室,3和4复用.
    • 如果根据结束时间从早到晚,那么首先4会和1尝试合,发现冲突,于是4和2合,其余都合不了,总共3间,并不是最优解

贪心解法

  • 用一个vector记录现有会议室的结束时间 e n d T i m e L i s t endTimeList endTimeList
  • 对所有会议按照开始时间从早到晚排序
  • 遍历所有的会议 a i a_i ai,在当前会议室集合 e n d T i m e L i s t endTimeList endTimeList找最早结束的会议 a e a r l i s t a_{earlist} aearlist,判断 a e a r l i s t a_{earlist} aearlist的结束时间是否早于 a i a_i ai的开始时间,如果早于则说明会议室能复用,在 e n d T i m e L i s t endTimeList endTimeList中更新改会议室的结束时间.否则则新开一间会议室,在 e n d T i m e L i s t endTimeList endTimeList中记录.
  • 时间复杂度为 O ( n 2 ) O(n^2) O(n2)
#include <bits/stdc++.h>

//#define debug
#define PII pair<int,int>
#define  x first
#define  y second
using namespace std;

const int N = 100;
PII a[N];
vector<int> end_time_list;//现有会议室的结束时间集合


int main() {
#ifdef debug
    freopen("in.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0);
    int n = 0;
    while (true) {
        int t1, t2;
        cin >> t1 >> t2;
        if (!t1 && !t2)break;
        a[n++] = {t1, t2};
    }
    sort(a, a + n, [&](PII p1, PII p2) { return p1.x < p2.x; });
    for (int i = 0; i < n; ++i) {
        int idx = 0;//最早结束会议室的下标
        for (int j = 0; j < end_time_list.size(); ++j) {
            //找最早结束的会议
            if (end_time_list[j] < end_time_list[idx]) idx = j;
        }
        if (end_time_list.size() && end_time_list[idx] <= a[i].x)//当前会议的开始时间在最早结束的后面,可以复用会议室
            end_time_list[idx] = a[i].y;
        else //不能复用,新增一个会议室
            end_time_list.push_back(a[i].y);
    }
    cout << end_time_list.size() << endl;
    return 0;
}

堆优化解法

  • 从一个集合中找最小值并且更新的操作可以用堆在 O ( log ⁡ n ) O(\log n) O(logn)的时间复杂度内完成
  • 用C++中的优先队列实现小顶堆
#include <bits/stdc++.h>

//#define debug
#define PII pair<int,int>
#define  x first
#define  y second
using namespace std;

const int N = 100;
PII a[N];
priority_queue<int, vector<int>, greater<int>> heap;//最早的结束时间


int main() {
#ifdef debug
    freopen("in.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0);
    int n = 0;
    while (true) {
        int t1, t2;
        cin >> t1 >> t2;
        if (!t1 && !t2)break;
        a[n++] = {t1, t2};
    }
    sort(a, a + n, [&](PII p1, PII p2) { return p1.x < p2.x; });
    for (int i = 0; i < n; ++i) {
        if (!heap.empty() && heap.top() <= a[i].x) {
            //复用会议室
            heap.pop();
        }
        heap.push(a[i].y);
    }
    cout << heap.size() << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u011459717/article/details/128531372
今日推荐