题目描述

✅ 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 也不会变小。先前检查过的交集都无法容纳会议,被丢弃区间又不可能形成遗漏的可行配对,因此第一次找到的合法交集就是全局最早答案。

解题步骤

  1. 分别将 slots1、slots2 按开始时间升序排序,两个指针从零开始。
  2. 计算当前交集的 start、end,若长度足够,返回从 start 开始的固定时长会议。
  3. 否则比较两段结束时间,推进结束较早的一侧;相同时按代码推进第二侧。
  4. 重复直到找到答案或任一数组耗尽。交集恰好等于所需时长也有效,只有一个共同端点则无法容纳正时长会议。

代码实现

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. 员工空闲时间 困难 原题给忙碌日程并求所有共同空闲区间,本题直接给可用区间且只找最早合格会议。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/57848924
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!