如何基于数组表示的时间槽列表计算空闲时段(NOR操作)?
解决时间槽的NOR操作:找出未被占用的空闲时段
嘿,这个需求其实挺常见的,核心就是把时间槽处理成容易计算的格式,然后按顺序排查空隙就行。我给你理清楚步骤,再附上可运行的代码示例:
核心思路
- 先把所有时间(包括总区间的起止和每个槽的起止)转换成总分钟数,这样加减计算就完全不用管小时和分钟的换算问题,特别省心。
- 对所有时间槽按开始时间排序,如果原列表是无序的,这一步必须做,不然没法连续检查相邻槽的空隙。
- 从总区间的开始时间出发,依次对比当前槽的开始时间和上一个区间的结束时间:如果前者大于后者,中间的就是空闲时段。
- 别忘了处理总区间的「开头空隙」(第一个槽开始晚于总区间起点)和「结尾空隙」(最后一个槽结束早于总区间终点)。
代码实现(Java示例)
先写个工具方法把{小时,分钟}数组转成总分钟数:
private static int convertToMinutes(int[] time) { return time[0] * 60 + time[1]; }
然后写核心方法,输入总区间的起止、时间槽列表,返回空闲时段列表:
import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; public class TimeSlotNOR { public static List<int[][]> findFreeSlots(int[] totalStart, int[] totalEnd, List<int[][]> occupiedSlots) { List<int[][]> freeSlots = new ArrayList<>(); // 1. 把所有时间转成分钟数 int totalStartMin = convertToMinutes(totalStart); int totalEndMin = convertToMinutes(totalEnd); // 2. 对占用的时间槽按开始时间排序 occupiedSlots.sort(Comparator.comparingInt(slot -> convertToMinutes(slot[0]))); // 3. 初始化上一个结束时间为总区间的开始 int lastEndMin = totalStartMin; for (int[][] slot : occupiedSlots) { int slotStartMin = convertToMinutes(slot[0]); int slotEndMin = convertToMinutes(slot[1]); // 如果当前槽的开始时间晚于上一个结束时间,说明有空隙 if (slotStartMin > lastEndMin) { // 把分钟数转回到{小时,分钟}格式 int[] freeStart = {lastEndMin / 60, lastEndMin % 60}; int[] freeEnd = {slotStartMin / 60, slotStartMin % 60}; freeSlots.add(new int[][]{freeStart, freeEnd}); } // 更新上一个结束时间为当前槽的结束时间(取较大值,防止重叠槽的情况) lastEndMin = Math.max(lastEndMin, slotEndMin); } // 4. 处理总区间结尾的空隙 if (lastEndMin < totalEndMin) { int[] freeStart = {lastEndMin / 60, lastEndMin % 60}; int[] freeEnd = {totalEndMin / 60, totalEndMin % 60}; freeSlots.add(new int[][]{freeStart, freeEnd}); } return freeSlots; } private static int convertToMinutes(int[] time) { return time[0] * 60 + time[1]; } // 测试示例 public static void main(String[] args) { // 总区间:9:00-17:00 int[] totalStart = {9, 0}; int[] totalEnd = {17, 0}; // 占用的时间槽:09:00-14:00 和 16:00-17:00 List<int[][]> occupiedSlots = new ArrayList<>(); occupiedSlots.add(new int[][]{{9, 0}, {14, 0}}); occupiedSlots.add(new int[][]{{16, 0}, {17, 0}}); List<int[][]> freeSlots = findFreeSlots(totalStart, totalEnd, occupiedSlots); // 打印结果 for (int[][] slot : freeSlots) { System.out.printf("%d:%02d-%d:%02d%n", slot[0][0], slot[0][1], slot[1][0], slot[1][1]); } // 输出:14:00-16:00,和你的示例一致 } }
关键细节说明
- 时间转换:把
{小时,分钟}转成总分钟数是核心,避免了处理跨小时的计算错误(比如13:59到14:01,直接用分钟数差就是2,非常直观)。 - 排序处理:如果原时间槽列表是乱序的(比如先给16:00-17:00,再给9:00-14:00),排序后才能正确遍历检查空隙。
- 重叠槽处理:用
Math.max(lastEndMin, slotEndMin)更新上一个结束时间,就算有重叠的占用槽(比如一个槽是10:00-15:00,另一个是13:00-16:00),也能正确合并成一个连续的占用区间,不会出错。 - 边界情况:比如所有时间槽都覆盖了总区间,那返回的空闲列表就是空的;如果总区间里没有任何占用槽,就返回整个总区间。
内容的提问来源于stack exchange,提问作者nuggetbram
相关产品推荐
相关产品推荐

