如何准确有效地计算多个时间间隔之间的总重叠?

问题描述 投票:0回答:2

我有两个时间窗:白天的时间每天从07.00到19.00,夜间的时间每天从19.00到7.00。然后有给定的开始和结束时间[s,e]的“维护间隔”。 s和e是实数,表示从第一天的午夜起算的小时数。对于任何维护间隔,我想确定它是白天最大的部分还是夜间最大的部分。

因此,我开始尝试确定维护间隔在白天的总时间和维护间隔在夜间的总时间,但是我找不到如何很好地做到这一点的方法。

某些输入和输出:

  1. [[20,22] =夜间2小时,白天0小时(因此将其归为夜间维护间隔)]
  2. [10,25] =白天9个小时,夜间6个小时(白天维护间隔)
  3. [10,49] =白天21个小时,夜间18个小时(白天维护间隔)

还要观察2和3之间的相似性。第三个间隔持续的时间更长(比第二个间隔长一天),但是结果是相同的。一个不错的解决方案可能会受益于此特性,丢弃所有与最终解决方案无关紧要的“全天候”。

[最好,我获得了一种优雅的解决方案,可以轻松地以数学符号显示(而不是整个算法)。

希望任何人都可以提供帮助!

algorithm math time intervals overlap
2个回答
0
投票

开始总是标准化的,但是结束需要标准化-只是减去开始后整整几天。现在e不超过48

e = e - ((e - s) div 24) * 24

现在我们有s的三个变体,以及每个变体的e的三个可能范围:

 s    0..7                 7..19                   19..24
     -----------------------------------------------------
 e    s..7                 s..19                   s..31
      7..19                19..31                  31..43 
      19..s+24 (<31)       31..s+24 (<43)          43..s+24 (<48)

创建if条件并不困难-较长但易于阅读

d = 0
n = 0
if s <= 7:
    if e <= 7:
       n += e - s
    elif e <= 19:
       n += 7 - s
       d += e - 7
    else   
       n += 7 - s + e - 19
       d += 12
 elif s <= 19:
    if e <= 19:
       d += e - s
    elif e <= 31:
       d += 19 - s
       n += e - 19
    else   
       d += 19 - s + e - 31
       n += 12
 else
    if e <= 31:
       n += e - s
    elif e <= 43:
       n += 31 - s
       d += e - 31
    else   
       n += 31 - s + e - 43
       d += 12

现在挤压类似的动作(未彻底检查):

nd = [0, 0]     # night and day hours
halfdays = (s + 5) // 12   
# 0 for the 1st variant, 1 for the 2nd, 2 for the 3rd

halfhours =  halfdays * 12   #time shift
s -= halfhours
e -= halfhours

cur = halfdays & 1
next = 1 - cur
if e <= 7:
       nd[cur] += e - s
    elif e <= 19:
       nd[cur] += 7 - s
       nd[next] += e - 7
    else   
       nd[cur] += e - s - 12
       nd[next] += 12

0
投票

这可能比效率更高。除非间隔持续数年,否则您不必担心效率,甚至在这种情况下也不必担心。

首先让我们声明一些带有漂亮名称的常量。我的代码是Java,但是要转换成您选择的编程语言应该不难。

private static int HOURS_PER_DAY = 24;
private static double DAY_BEGINS = 7; 
private static double NIGHT_BEGINS = 19;

现在我的算法是这样的:

    // Maintenance interval to calculate;
    // numbers are numbers of hours since start of the day where the shift begins
    double start = 10;
    double end = 49;

    if (start < 0 || start >= 24 || end < start) {
        throw new IllegalStateException();
    }

    double nightHours = 0;
    double dayHours = 0;
    double time = start;
    double nextNightBegins = NIGHT_BEGINS;
    double nextDayBegins = DAY_BEGINS;
    if (time >= DAY_BEGINS) {
        nextDayBegins += HOURS_PER_DAY;
        if (time < NIGHT_BEGINS) { // time is in day time
            // establish loop invariant
            dayHours += NIGHT_BEGINS - time;
            time = NIGHT_BEGINS;
        }
        nextNightBegins += HOURS_PER_DAY;
    }
    // Loop invariant:
    // time <= nextDayBegins < nextNightBegins || time == end.
    // Hours up to time have been summed into dayHours and nightHours.
    while (time < end) {
        assert time <= nextDayBegins : "" + time + " >= " + nextDayBegins;
        assert nextDayBegins < nextNightBegins;
        double nightHoursUntil = Math.min(nextDayBegins, end);
        nightHours += nightHoursUntil - time;
        time = nightHoursUntil;
        nextDayBegins += HOURS_PER_DAY;
        if (time < end) {
            double dayHoursUntil = Math.min(nextNightBegins, end);
            dayHours += dayHoursUntil - time;
            time = dayHoursUntil;
            nextNightBegins += HOURS_PER_DAY;
        }
    }
    assert time == end;

    System.out.format(Locale.ENGLISH,
            "%.2f hours during nighttime, %.2f hours during daytime%n",
            nightHours, dayHours);
    if (nightHours > dayHours) {
        System.out.println("Nighttime maintenance interval)");
    } else if (nightHours < dayHours) {
        System.out.println("Daytime maintenance interval");
    } else { // they are equal
        System.out.println("Undecided maintenance interval)");
    }

代码显示的输出是:

18.00 hours during nighttime, 21.00 hours during daytime
Daytime maintenance interval

我更喜欢not利用这样的事实,即您的边界白天和黑夜具有相等的长度(每个长度12小时)。有一天进行了更改,因此夜晚从18:30开始,因此您不必冒险程序会默认开始发出错误的分类。在上面的算法中,您可以更改常量(在示例中从19更改为18.5),代码仍然可以使用。

我曾经考虑过使用Java的LocalTime,但是LocalTime最多只能使用23:59:59.999999999,所以不会立即生效。

© www.soinside.com 2019 - 2024. All rights reserved.