会议室 图解题解
这道题到底在问什么
- 输入
- meetings = [[0,30],[5,10],[15,20]]
- 输出
- false(0~30 和 5~10 撞了)
- 输入
- meetings = [[7,10],[2,4]]
- 输出
- true(两场不重叠)
先想最直接的笨办法
排序结束!所有会议按开始时间从早到晚站好队:[1,3] [4,7] [7,9] [9,12] [14,18] [19,22]。柱子高度从左到右递增。下面挨个检查相邻两场会不会撞车。(动画第 22 步)
最优解:一步一步想明白
- 3记住判定式:排好序后,只要出现「前一场结束 > 后一场开始」,就是撞车。下面每一帧都在套这一句。
- 45 场会议按你给的顺序排着:[14,18] [1,3] [9,12] [4,7] [19,22] [7,9]。柱子的高度就是它的开始时间,现在还乱着,先按开始时间排序。
- 5第 1 趟找最早开场:拿候选 [1,3](开始 1)和目前最早的 [1,3] 比。它更早,记下它当新的最早。
- 6第 1 趟找最早开场:拿候选 [9,12](开始 9)和目前最早的 [1,3] 比。没它早,最早仍是 [1,3]。
- 7第 1 趟找最早开场:拿候选 [4,7](开始 4)和目前最早的 [1,3] 比。没它早,最早仍是 [1,3]。
- 8第 1 趟找最早开场:拿候选 [19,22](开始 19)和目前最早的 [1,3] 比。没它早,最早仍是 [1,3]。
- 9第 1 趟找最早开场:拿候选 [7,9](开始 7)和目前最早的 [1,3] 比。没它早,最早仍是 [1,3]。
- 10选定后 [1,3] 归位(绿色)。最左边 1 场已按开始时间从早到晚排好。
- 11第 2 趟找最早开场:拿候选 [9,12](开始 9)和目前最早的 [9,12] 比。它更早,记下它当新的最早。
- 12第 2 趟找最早开场:拿候选 [4,7](开始 4)和目前最早的 [4,7] 比。它更早,记下它当新的最早。
- 13第 2 趟找最早开场:拿候选 [19,22](开始 19)和目前最早的 [4,7] 比。没它早,最早仍是 [4,7]。
- 14第 2 趟找最早开场:拿候选 [7,9](开始 7)和目前最早的 [4,7] 比。没它早,最早仍是 [4,7]。
- 15选定后 [4,7] 归位(绿色)。最左边 2 场已按开始时间从早到晚排好。
- 16第 3 趟:在还没归位的会议里挑开始最早的——是 [7,9](高亮),开始 7。
- 17选定后 [7,9] 归位(绿色)。最左边 3 场已按开始时间从早到晚排好。
- 18第 4 趟:在还没归位的会议里挑开始最早的——是 [9,12](高亮),开始 9。
- 19选定后 [9,12] 归位(绿色)。最左边 4 场已按开始时间从早到晚排好。
- 20第 5 趟:在还没归位的会议里挑开始最早的——是 [14,18](高亮),开始 14。
- 21选定后 [14,18] 归位(绿色)。最左边 5 场已按开始时间从早到晚排好。
- 22排序结束!所有会议按开始时间从早到晚站好队:[1,3] [4,7] [7,9] [9,12] [14,18] [19,22]。柱子高度从左到右递增。下面挨个检查相邻两场会不会撞车。
- 23检查第 1 对:前一场 [1,3] 在 3 结束,后一场 [4,7] 在 4 才开。3 ≤ 4,没重叠,继续看下一对。
- 24检查第 2 对:前一场 [4,7] 在 7 结束,后一场 [7,9] 在 7 才开。7 ≤ 7,没重叠,继续看下一对。
- 25检查第 3 对:前一场 [7,9] 在 9 结束,后一场 [9,12] 在 9 才开。9 ≤ 9,没重叠,继续看下一对。
- 26检查第 4 对:前一场 [9,12] 在 12 结束,后一场 [14,18] 在 14 才开。12 ≤ 14,没重叠,继续看下一对。
- 27检查第 5 对:前一场 [14,18] 在 18 结束,后一场 [19,22] 在 19 才开。18 ≤ 19,没重叠,继续看下一对。
- 28所有相邻会议都不重叠,这一堆会议可以全部参加。答案是 true。
⚠️ 容易写错的地方
✗ 错:不排序就直接两两比较
✓ 对:先按开始时间排序,再比相邻对
没排序时重叠的两场可能离得很远,只比相邻会漏判;排序后重叠必出现在相邻位置
✗ 错:把判定写成「前结束 ≥ 后开始」
✓ 对:用「前结束 > 后开始」才算重叠
前一场 10 点结束、后一场正好 10 点开,端点相接不算冲突(左闭右开),用 ≥ 会误判
✗ 错:发现一处重叠还继续找完
✓ 对:一旦撞车立刻 return false
只要存在任意一对重叠就不可能全参加,没必要扫完,提前返回更快
完整代码(Python / C++ / Java)
Python
def canAttendMeetings(meetings):
meetings.sort(key=lambda m: m[0]) # 按开始时间排序
for i in range(1, len(meetings)):
# 前一场的结束 比 后一场的开始 还晚 → 重叠
if meetings[i-1][1] > meetings[i][0]:
return False
return TrueC++
bool canAttendMeetings(vector<vector<int>>& a){
sort(a.begin(), a.end()); // 默认按首元素(开始)排
for (int i = 1; i < a.size(); i++)
if (a[i-1][1] > a[i][0]) // 前结束 > 后开始
return false;
return true;
}Java
public boolean canAttendMeetings(int[][] a) {
Arrays.sort(a, (x, y) -> x[0] - y[0]); // 按开始时间排
for (int i = 1; i < a.length; i++)
if (a[i-1][1] > a[i][0]) // 前结束 > 后开始
return false;
return true;
}复杂度
时间
O(n log n)
瓶颈在排序;排完只需一趟 O(n) 线性扫描
空间
O(1)
原地排序、只用常数个变量(不算排序自身递归栈)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 会议室 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么是按「开始时间」排序,而不是结束时间?+
按开始时间排序后,会议在时间轴上从左到右依次开场,相邻两场的「前结束 vs 后开始」正好能直接判重叠。这题只问能否全参加,不需要像「会议室数量」那题用结束时间或最小堆。
端点相接算不算重叠?比如 [1,5] 和 [5,8]。+
不算。区间通常按「左闭右开」理解,前一场 5 点结束、后一场 5 点开始,刚好接上不冲突。所以判定要用严格大于:前结束 > 后开始 才是重叠。
如果进一步问「最少需要几间会议室」怎么办?+
那是 LC253,思路升级:把所有会议按开始排序,用一个最小堆存当前正在进行的会议的结束时间;每来一场新会议,若堆顶(最早结束的)已 ≤ 新会议开始,就复用那间房,否则新开一间。堆的大小峰值就是答案。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 会议室 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。