← 返回题目列表

会议室问题:一个人能否参加所有会议?(LeetCode 252)

高频 简单 第 2 / 24 题 更新于 2026/07/28
区间问题会议室排序重叠判断

简化版

给一组会议时间 intervals[i] = [start, end],判断一个人能否参加全部会议——即这些会议是否两两不重叠。做法极简:按开始时间升序排序,然后检查相邻两个会议是否重叠——只要有某个会议的开始时间 < 上一个会议的结束时间,就冲突,返回 false;全都不冲突则 true。

详细版

boolean canAttendMeetings(int[][] intervals) {
    Arrays.sort(intervals, (a, b) -> a[0] - b[0]);   // 按开始时间升序
    for (int i = 1; i < intervals.length; i++) {
        if (intervals[i][0] < intervals[i - 1][1]) { // 当前开始 < 上一个结束 → 重叠
            return false;
        }
    }
    return true;
}
  • 排序后只需比相邻:按开始时间排序后,若存在重叠,一定发生在相邻两个会议之间。
  • 重叠判断当前.start < 上一个.end(相接 == 不算冲突,前一个结束的瞬间可以开始下一个)。
  • 复杂度:排序 O(n log n),扫描 O(n)。

完整版教学

一、题意:等价于「区间是否两两不重叠」

「一个人能参加所有会议」意味着任意两个会议在时间上都不冲突——也就是所有区间两两不重叠。只要发现任何一对重叠,就说明这个人分身乏术,返回 false。这是最基础的区间题,是会议室 II(求最少会议室数)的前置。

二、为什么排序后只需检查相邻

两两检查是 O(n²)。按开始时间升序排序后,可以只检查相邻对,O(n) 搞定。原因:排序后开始时间单调不减。如果会议 i 和某个更早的会议 j(j < i−1)重叠,那么因为排序,中间的会议 i−1 的开始时间夹在 j 和 i 之间——它要么也和 j 重叠(那相邻对 j 与 j+1 就会先被发现),要么整个链条上必有一对相邻重叠。严格说:若排序后没有任何相邻对重叠,则全局无重叠。所以只查相邻就够。

三、重叠判断的边界:< 还是 <=

判断「当前会议开始 vs 上一个会议结束」:

  • intervals[i][0] < intervals[i-1][1] → 冲突。用严格小于,因为会议 [9,10][10,11] 不冲突——上一个 10 点结束,下一个正好 10 点开始,一个人能无缝衔接。端点相接不算重叠。
  • 若写成 <=,会把相接的会议误判为冲突。这是最常见的边界错误。

(当然,若某题定义「10 点结束到 10 点开始也算冲突」,才用 <=;按常规会议语义是 <。)

四、和其他区间题的关系

  • 会议室 II(253):不是判断能否参加,而是求「最少需要几间会议室」= 求「任意时刻最多有几个会议同时进行」,要用扫描线/最小堆,比本题复杂一档。本题是它的基础。
  • 合并区间 56 / 无重叠区间 435:都以「排序 + 判相邻重叠」为地基,本题是这套地基最纯粹的形态。

五、易错点

  • 忘记排序:不排序直接比相邻是错的,输入本身无序。
  • 重叠符号写反<<= 的选择要匹配「相接算不算冲突」,会议语义下用 <
  • 比较对象错:是「当前的 start」和「上一个的 end」比,别写成 start 比 start 或 end 比 end。

六、排序键、扫描不变量与边界语义

本题扫描成立的结构是:按开始时间排序后,只需检查相邻会议;若当前 start 小于前一 end 即冲突。

若非相邻两段冲突,中间会议的开始更早,因此相邻检查必已发现冲突

数字推演:[0,30],[5,10],[15,20] 排序后第一对立即冲突;[0,5],[5,10] 在半开语义下不冲突。

扫描过程中要始终说明已经处理部分被压缩成什么状态,以及为什么更早区间不必再看。实现边界是:会议通常按 [start,end),端点相等可衔接;排序会修改原数组时需说明。

记忆钩子:区间题先写端点语义,再选排序键;小于还是小于等于不是代码风格,而是问题定义。

七、方法对比与专项测试

问题结构常用工具
静态合并或覆盖排序后线性扫描
选择最多不重叠按右端排序的贪心
最大同时重叠扫描线或最小堆
两个有序列表求交双指针
动态预约有序树或线段树

测试必须覆盖空输入、单区间、完全分离、完全嵌套、链式重叠、相同起点或终点,以及端点恰好相接。若排序比较器用端点相减,还要加入整数极值检查溢出。

正确性复核要落到本题的排除逻辑:按开始时间排序后,只需检查相邻会议;若当前 start 小于前一 end 即冲突。这保证扫描指针越过某段后,它不可能再与未来候选形成更优或遗漏的答案。

已处理区间 ──压缩为边界/堆/结果尾段──> 当前区间
       │                                  │
       └─ 已由排序与端点关系证明无需回看 ─┘
当前决策完成后,指针只向右移动

在数字样例“[0,30],[5,10],[15,20] 排序后第一对立即冲突;[0,5],[5,10] 在半开语义下不冲突”上,应逐轮写出被保留的边界和被丢弃的区间。若某一步无法解释为什么丢弃安全,就说明排序键、端点不等号或状态定义仍有问题。

工程上还要单独确认:会议通常按 [start,end),端点相等可衔接;排序会修改原数组时需说明。这些条件变化会直接改变重叠判定或所需数据结构,不能只修改一个比较符后沿用原证明。

八、常见误区与追问

  • 误区:必须比较所有区间对。 排序后相邻检查足够。
  • 误区:end==next.start 算冲突。 会议常用半开区间,可无缝衔接。
  • 误区:按结束时间排同样直观。 判断冲突按开始时间更容易保证相邻覆盖。
  • 追问:为什么非相邻冲突会被发现? 中间区间开始更早,至少有一对相邻冲突。
  • 追问:复杂度如何? 排序 O(n log n),扫描 O(n)。
  • 追问:能返回冲突会议吗? 扫描时记录第一对相邻冲突即可。

九、加强记忆

会议室 I(能否参加全部)= 判断区间是否两两不重叠。做法:按开始时间升序排序,检查每个相邻对——当前.start < 上一个.end 就冲突返回 false,全程无冲突返回 true。排序后「无相邻重叠 ⇒ 全局无重叠」,故只需 O(n) 扫相邻。重叠用严格 <(会议相接如 [9,10][10,11] 不冲突)。它是会议室 II(求最少会议室数,需扫描线/堆)的基础。O(n log n)。