这个问题的答案来自最小公倍数的概念.无论这两个序列的周期是什么,总会有一个时间点,它们都在同一时间点开始一个新的周期,可能会有一个偏移量.从那时起,发生的一切都将是第一个周期中发生的事情的重演.
要得到这个周期的长度,只需要找到两个重复间隔中最小的公倍数.在最坏的情况下,当两个间隔中的一个是质数时,该周期将是interval1 * interval2
.如果这些数字不是素数,它们所共有的任何公因子都将意味着周期长度将会缩短.以下是将计算最小公倍数的Python函数:
def compute_lcm(a, b):
return abs(a*b) // math.gcd(a, b)
如果这两个序列同时开始,那么从现在开始,一切都会非常简单.但如果这两个时间间隔开始的时间不同,事情就会变得更加复杂.我们基本上必须考虑到这样一个事实,即单个周期不会捕获所有这两个序列,因为一个序列可能在单个周期开始之前开始,而另一个序列可能在周期开始之后结束.
我推理出了必须做什么才能考虑到两个序列的偏移量,还考虑了可能会将事情延长一点的持续时间.我可能不太明白这一点.我已经创建了几个示例,手动推理出重叠部分是什么,然后在我的代码中运行这些示例,我得到了相同的答案.所以它应该是正确的.
所以这就是它血淋淋的荣耀:
import math
def compute_lcm(a, b):
return abs(a*b) // math.gcd(a, b)
# First sequence
# 15-20, 30-35, 45-50, 60-65
seq1 = {
'start': 15,
'repeat_interval': 15,
'duration': 5,
'extra': 0,
}
# Second sequence
# 5-11, 25-31, 45-51, 65-71
seq2 = {
'start': 5,
'repeat_interval': 20,
'duration': 6,
'extra': 0,
}
# Overlap by inspection: 30, 45-49
# Compute the magic value, the number of minutes at which the two sequences start over at the same time offset as for the initial cycle.
lcm = compute_lcm(seq1['repeat_interval'], seq2['repeat_interval'])
overall_start = 0
# This stuff's a bit crazy, I know. Sorry.
# For whichever sequence starts last, add extra repeat intervals to
# the start of it so that it covers the entire main cycle, which
# starts where the other cycle starts.
if seq1['start'] > seq2['start']:
while seq1['start'] > seq2['start']:
seq1['start'] -= seq1['repeat_interval']
seq1['extra'] += seq1['repeat_interval']
overall_start = seq1['start']
else:
while seq2['start'] > seq1['start']:
seq2['start'] -= seq2['repeat_interval']
seq2['extra'] += seq2['repeat_interval']
overall_start = seq2['start']
# Compute a worst case length for the 'minutes' array we'll use
# to tally to find the overlaps.
total_length = lcm + max(seq1['extra'], seq2['extra']) + max(seq1['duration'], seq2['duration'])
offset = -min(seq1['start'], seq2['start'])
# Create an array such that each element in the array represents a minute of time
minutes = [0] * total_length
# Now walk through each sequence from its start. For each, compute each interval, and then loop over that
# interval, incrementing the value of each minute of it in the 'minutes' array to record that the sequence
# was "on" during that minute.
#
# NOTE: I chose to consider an interval's start and ent times to be exlusive of the last minute. So the
# interval 10-15 consists of the minutes 10, 11, 12 and 13. I could have gone the other way, including the
# last minute in each interval. If that's what is desired, I leave making that small change as an exercise for the OP
for seq in (seq1, seq2):
t = seq['start']
while t < seq['start'] + lcm + seq['extra']:
for o in range(seq['duration']):
tt = offset + t + o
minutes[tt] += 1
t += seq['repeat_interval']
# At this point, overlaps consist of values in the 'minutes' array that have a value of 2, meaning
# that both sequences were "on" during that minute. Walk through the array, printing out each
# minute that was part of an overlap
for i in range(total_length):
if minutes[i] > 1:
print(i-offset)
结果:
30
45
46
47
48
49
如果您想要生成更多的重叠分钟数,只需继续迭代更多的分钟值,并对分钟值执行mod操作以在‘Minents’数组中进行查找.所以:
count = minutes[m % lcm]
如果count==2,则对于任何值"m",分钟"m"都是重叠的一部分.
哦..还有一件事,也许这就是我的答案遗失绿色支票的地方.此答案不考虑以小时和分钟指定的时间.它只是给出了计算重叠和计算最小必要周期长度的基本思想的答案,所有值都以分钟为单位表示.要在数小时或数天内执行此操作,只需将时间值转换为仅分钟表示即可.时区也会增加复杂性,但您只需补偿分钟值就可以考虑任何时区转换.