面试题:判断两个周期性预约是否存在时间重叠
嘿,这个问题我之前做企业日历预约系统的时候正好碰到过,当时踩了不少重复规则解析和边界处理的坑,分享下我实际验证过的解决方案思路:
周期性预约冲突检测完整方案
核心逻辑
本质是要找到两个重复时间序列中,是否存在至少一个时间区间满足重叠条件。因为是周期性的,不可能无限遍历所有可能的预约,所以核心是要圈定有限的检查范围,同时用高效的逻辑判断冲突。
具体实施步骤
1. 先把重复规则解析成可计算的逻辑
首先得把自然语言的重复规则转换成程序能识别的生成规则,比如:
- 每日重复:比如「每2天」,就是从起始时间开始,每次加2天的时间间隔
- 每周重复:比如「每3周的周二」,就是每隔21天(3×7),筛选出周二的日期
- 每月重复:分两种场景单独处理:
- 固定日期:比如「每2个月的17日」,每隔N个月取当月17日(要注意月末边界,比如2月没有30日,得和业务确认是调整到月末还是跳过)
- 固定周几:比如「每月第三个周二」,需要写逻辑计算当月第K个星期X的具体日期
- 每年重复:比如「每2年的4月17日」,就是每隔2年,取当年4月17日的日期
2. 确定合理的检查范围
因为是无限重复的预约,不可能一直检查下去,通常的做法是:
- 如果两个预约都有结束时间,就取它们的有效时间交集作为检查范围
- 如果其中一个或两个没有结束时间,就设定一个业务合理的最大检查周期(比如10年,毕竟很少有人会预约10年后的重复事项)
- 在这个范围内如果没找到冲突,就认为长期内不会冲突,后续可以根据业务需求调整阈值
3. 时间区间重叠的判断逻辑
不管是单次还是重复预约,时间区间重叠的判断公式是通用的:
对于区间A(startA, endA)和区间B(startB, endB),当
startA < endB 且 startB < endA时,两个区间存在重叠。
这里要注意一个容易踩的坑:如果预约没有填写结束时间,必须先和业务方确认默认时长——是持续全天,还是默认1小时?这个规则不明确的话,后续的冲突判断全是错的。
4. 优化:用数学方法缩小检查范围
如果直接生成所有时间区间再遍历,大周期下会很耗时,可以用周期最小公倍数来优化:
- 比如两个每日重复的预约,间隔分别是2天和3天,最小公倍数是6天,只需要检查6天内的情况——如果有冲突,之后每6天都会重复冲突;如果没有,就永远不会冲突
- 每周、每月、每年的重复规则,也可以用类似的方法计算周期的最小公倍数,大幅减少需要检查的时间点
5. 边界情况必须处理
- 特殊日期:比如2月29日的年度重复预约,非闰年要调整到2月28日还是直接跳过?得和业务对齐
- 跨时区:所有时间必须统一转换到同一个时区(比如UTC)再计算,避免时区差导致的误判
- 单次预约:如果重复规则是「不重复」(虽然问题说的是周期性,但实际场景可能存在),直接判断单次时间区间是否重叠即可
伪代码示例
def check_recurring_overlap(appt1, appt2, max_check_years=5): # 解析重复规则,生成指定范围内的所有时间区间 appt1_intervals = generate_recurring_time_ranges(appt1, max_check_years) appt2_intervals = generate_recurring_time_ranges(appt2, max_check_years) # 遍历检查每个区间是否重叠 for start1, end1 in appt1_intervals: # 优化:只检查和当前时间区间接近的appt2区间,避免全量遍历 for start2, end2 in appt2_intervals: if start1 < end2 and start2 < end1: return True # 重置appt2的区间生成器,避免重复遍历 appt2_intervals = generate_recurring_time_ranges(appt2, max_check_years) return False
内容的提问来源于stack exchange,提问作者tienph




