【贪心-2】253.会议室 II

题目描述:

给定一个会议时间安排的数组 intervals,每个会议时间包括开始和结束的时间 [start, end],计算至少需要多少间会议室才能满足所有会议安排。

示例:

复制代码
输入: [[0, 30], [5, 10], [15, 20]]
输出: 2

输入: [[7, 10], [2, 4]]
输出: 1

解题思路:

方法一:排序 + 小根堆(推荐)

核心思路:

  1. 按开始时间排序所有会议

  2. 用小根堆 维护当前正在使用的会议室的结束时间

  3. 遍历每个会议:

    • 如果堆顶(最早结束的会议)≤ 当前会议的开始时间,说明有会议室空闲,弹出堆顶

    • 把当前会议的结束时间压入堆

  4. 堆的大小就是所需的最少会议室数量

具体过程示例:

intervals = [[0, 30], [5, 10], [15, 20]]

排序后:[[0, 30], [5, 10], [15, 20]]

会议 堆操作 堆内容 说明
0, 30 push(30) 30 第一间会议室
5, 10 堆顶30 > 5,push(10) 10, 30 需要第二间
15, 20 堆顶10 ≤ 15,pop,push(20) 20, 30 复用第一间

堆大小 = 2 ✅

代码实现:

cpp 复制代码
class Solution {
public:
    int minMeetingRooms(vector<vector<int>>& intervals) {
        if (intervals.empty()) return 0;
        
        // 按开始时间排序
        sort(intervals.begin(), intervals.end());
        
        // 小根堆,存储结束时间
        priority_queue<int, vector<int>, greater<int>> pq;
        
        for (auto& interval : intervals) {
            // 如果有会议室空闲,弹出最早结束的
            if (!pq.empty() && pq.top() <= interval[0]) {
                pq.pop();
            }
            pq.push(interval[1]);
        }
        
        return pq.size();
    }
};

复杂度分析:

维度 复杂度 说明
时间复杂度 O(n log n) 排序 + 每个会议一次堆操作
空间复杂度 O(n) 堆最多存储 n 个结束时间

方法二:扫描线

思路:

把每个会议拆成两个事件:

  • 开始:+1(需要一间会议室)

  • 结束:-1(释放一间会议室)

按时间排序所有事件,累加计数,最大值就是所需会议室数。

关键 :同一时间有开始和结束,结束优先处理(先释放再占用)。

具体过程示例:

intervals = [[0, 30], [5, 10], [15, 20]]

事件:(0,+1), (5,+1), (10,-1), (15,+1), (20,-1), (30,-1)

时间 事件 计数 最大值
0 +1 1 1
5 +1 2 2
10 -1 1 2
15 +1 2 2
20 -1 1 2
30 -1 0 2

结果:2 ✅

代码实现:

cpp 复制代码
class Solution {
public:
    int minMeetingRooms(vector<vector<int>>& intervals) {
        vector<pair<int, int>> events;
        for (auto& interval : intervals) {
            events.push_back({interval[0], 1});   // 开始
            events.push_back({interval[1], -1});  // 结束
        }
        
        // 按时间排序,同一时间结束优先(-1 在前)
        sort(events.begin(), events.end(), [](const pair<int,int>& a, const pair<int,int>& b) {
            if (a.first == b.first) return a.second < b.second;
            return a.first < b.first;
        });
        
        int count = 0, maxRooms = 0;
        for (auto& [time, delta] : events) {
            count += delta;
            maxRooms = max(maxRooms, count);
        }
        
        return maxRooms;
    }
};

复杂度分析:

维度 复杂度 说明
时间复杂度 O(n log n) 排序事件
空间复杂度 O(n) 事件数组

方法三:双指针

思路:

把开始时间和结束时间分别排序,用两个指针比较:

  • 如果 start[s] < end[e]:新会议开始,需要新会议室,count++,s++

  • 否则:有会议结束,释放会议室,count--,e++

代码实现:

cpp 复制代码
class Solution {
public:
    int minMeetingRooms(vector<vector<int>>& intervals) {
        int n = intervals.size();
        vector<int> starts(n), ends(n);
        
        for (int i = 0; i < n; i++) {
            starts[i] = intervals[i][0];
            ends[i] = intervals[i][1];
        }
        
        sort(starts.begin(), starts.end());
        sort(ends.begin(), ends.end());
        
        int s = 0, e = 0, count = 0, maxRooms = 0;
        while (s < n) {
            if (starts[s] < ends[e]) {
                count++;
                s++;
            } else {
                count--;
                e++;
            }
            maxRooms = max(maxRooms, count);
        }
        
        return maxRooms;
    }
};

复杂度分析:

维度 复杂度 说明
时间复杂度 O(n log n) 排序两个数组
空间复杂度 O(n) 两个辅助数组

三种方法对比:

方法 时间复杂度 空间复杂度 代码复杂度 推荐度
排序 + 小根堆 O(n log n) O(n) 中等 ⭐⭐⭐⭐⭐
扫描线 O(n log n) O(n) 中等 ⭐⭐⭐⭐
双指针 O(n log n) O(n) 简单 ⭐⭐⭐⭐

总结:

要点 说明
核心思想 求重叠会议的最大数量
最优解法 排序 + 小根堆(维护结束时间)
关键操作 堆顶 ≤ 当前开始时间 → 复用会议室
时间复杂度 O(n log n)
空间复杂度 O(n)
相关推荐
小道士写程序3 小时前
Rust 中的字符串与切片(String 与 &str)
算法
圣保罗的大教堂3 小时前
leetcode 3863. 将一个字符串排序的最小操作次数 中等
leetcode
Tisfy3 小时前
LeetCode 3863.将一个字符串排序的最小操作次数:分类讨论(一次遍历)——简单易懂版
算法·leetcode·字符串·题解·分类讨论
小徐不徐说3 小时前
C++ 机器视觉入门:从零搭建 AOI 开发环境(OpenCV + CMake)
开发语言·c++·opencv
Young Doro3 小时前
从平衡表征到最小充分因果表征:端到端神经网络因果效应估计
算法
0+1113 小时前
算法 --递归
算法·leetcode
打工仔折腾 AI3 小时前
介入式脑机接口的跨尺度解码与闭环调控:从算法落地到后端工程实践
人工智能·后端·python·深度学习·算法·ai agent 实战
誰能久伴不乏3 小时前
【无标题】
c++·qt·机器人
大陈子编程4 小时前
C++ 背包九讲:从入门到精通的动态规划专题
开发语言·c++·动态规划
凤山老林4 小时前
授权模型只会RBAC?深入 ABAC 授权模型,实现权限判断做成策略引擎
大数据·数据库·算法