LeetCode 1229. 安排会议日程
题目描述
题意分析
两个人分别给出各自的空闲时间段,求能够共同参加、持续时间为
duration的最早会议,返回开始和结束时间,无解返回空结果。同一个人的空闲区间互不重叠,但输入未必有序;代码会分别排序两组区间。
解法:排序 + 双指针
核心思路
[!blue]
按开始时间排序后,用
i、j指向两人当前的空闲区间。共同空闲部分的起点是两者开始时间的较大值start,终点是两者结束时间的较小值end。当end - start >= duration时,从start开会就是这对区间能提供的最早方案,返回[start, start + duration]即可。如果当前交集不够长,就推进结束较早的一侧。设 A 比 B 先结束:B 后续区间与当前 B 不重叠且已经排序,所以它们的开始时间不早于当前 B 的结束时间,也就不早于 A 的结束时间。A 不可能再与 B 的后续区间形成正时长会议,丢弃 A 是安全的;B 则可能继续与 A 的后续区间配对。
两段结束时间相同时,丢弃任意一侧都安全,代码选择推进
j。每次至少推进一个指针,因此不会重复处理同一对区间,也不会陷入循环;某一方区间用尽后,剩余区间已没有可配对对象,可以返回空结果。每次移动指针,该侧的开始时间只会后移,所以候选交集的
start也不会变小。先前检查过的交集都无法容纳会议,被丢弃区间又不可能形成遗漏的可行配对,因此第一次找到的合法交集就是全局最早答案。
解题步骤
- 分别将
slots1、slots2按开始时间升序排序,两个指针从零开始。- 计算当前交集的
start、end,若长度足够,返回从start开始的固定时长会议。- 否则比较两段结束时间,推进结束较早的一侧;相同时按代码推进第二侧。
- 重复直到找到答案或任一数组耗尽。交集恰好等于所需时长也有效,只有一个共同端点则无法容纳正时长会议。
代码实现
class Solution {
public List<Integer> minAvailableDuration(int[][] slots1, int[][] slots2, int duration) {
Arrays.sort(slots1, (a, b) -> a[0] - b[0]);
Arrays.sort(slots2, (a, b) -> a[0] - b[0]);
int i = 0;
int j = 0;
while (i < slots1.length && j < slots2.length) {
int start = Math.max(slots1[i][0], slots2[j][0]);
int end = Math.min(slots1[i][1], slots2[j][1]);
if (end - start >= duration) {
// 取交集最早起点,只返回要求的会议时长。
return Arrays.asList(start, start + duration);
}
// 先结束的一段不可能再与对方后续区间产生更早会议。
if (slots1[i][1] < slots2[j][1]) {
i++;
} else {
j++;
}
}
return new ArrayList<>();
}
}
import "sort"
func minAvailableDuration(slots1 [][]int, slots2 [][]int, duration int) []int {
sort.Slice(slots1, func(i, j int) bool { return slots1[i][0] < slots1[j][0] })
sort.Slice(slots2, func(i, j int) bool { return slots2[i][0] < slots2[j][0] })
i, j := 0, 0
for i < len(slots1) && j < len(slots2) {
start := max(slots1[i][0], slots2[j][0])
end := min(slots1[i][1], slots2[j][1])
if end-start >= duration {
// 取交集最早起点,只返回要求的会议时长。
return []int{
start,
start + duration,
}
}
// 先结束的一段不可能再与对方后续区间产生更早会议。
if slots1[i][1] < slots2[j][1] {
i++
} else {
j++
}
}
return []int{
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
复杂度分析
- 时间复杂度:$O(m\log(m+1)+n\log(n+1))$,
m、n为两组区间数量。排序后每轮推进一个指针,扫描总计 $O(m+n)$。- 空间复杂度:扫描只使用 $O(1)$ 辅助空间;另计排序工作区,Java 对象数组排序为线性空间上界,Go 排序栈为对数级。
关键点总结
[!green]
- 起点取较晚者、终点取较早者,得到双方真正的共同空闲段。
- 同一人的区间互不重叠,是安全淘汰较早结束区间的关键前提。
- 候选起点单调后移,配合不遗漏的淘汰规则,保证首次成功最早。
易错点总结
[!yellow]
- 不排序就移动指针,无法保证候选顺序,也不能安全排除后续配对。
- 按开始时间更早的一侧移动,可能丢弃仍能与后续区间配对的长区间。
- 不要无条件同时推进两侧,结束较晚的一段还可能继续使用。
- 长度判断应为
>= duration,不能拒绝恰好够长的交集。- 返回的是所需会议时长,不是整个共同空闲段,结束时间应为
start + duration。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 986. 区间列表的交集 | 中等 | 先求两个有序可用时段的交集,本题再检查交集是否容纳所需会议时长。 |
| 759. 员工空闲时间 | 困难 | 原题给忙碌日程并求所有共同空闲区间,本题直接给可用区间且只找最早合格会议。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!