当前位置: 首页 > 知识库问答 >
问题:

从间隔列表中,查找所有间隔集,其中一个集合中的每个间隔与该集合中的所有间隔重叠

沈皓君
2023-03-14

与其查询具有开始和结束日期的间隔列表,不如从列表中检索仅与搜索开始和结束日期重叠的所有间隔,最好的方法是:

From a list of date intervals, 
Find all unique sets of intervals
Where every interval in each set overlaps with each other interval in that set

使用整数示例,以整数间隔列表[{1,3}、{2,4}、{4,5}、{5,7}、{6,8}]为例。在此列表中,以下是所有唯一的间隔集,其中每组中的每个间隔都相互重叠:

{ {1,3}, {2,4} }
{ {2,4}, {4,5} }
{ {4,5}, {5,7} }
{ {5,7}, {6,8} }

以下是DateInterval的类:

from datetime import datetime
class DateInterval(object):
    def __init__(self, start_time, end_time):
        self.start_time = datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S')
        seld.end_time = datetime.strptime(end_time, '%Y-%m-%d %H:%M:%S')

    ''' eq, gt, hash methods removed for clarity '''

我将收到按开始时间排序的间隔列表,如下所示:

intervals = [DateInterval(start_time='2015-01-01 08:00:00', end_time='2015-01-01 08:30:00'),
             DateInterval(start_time='2015-01-01 08:00:00', end_time='2015-01-01 10:00:00'),
             DateInterval(start_time='2015-01-01 09:00:00', end_time='2015-01-01 11:00:00'),
             DateInterval(start_time='2015-01-01 10:00:00', end_time='2015-01-01 12:00:00'),
             DateInterval(start_time='2015-01-01 13:00:00', end_time='2015-01-01 16:00:00'),
             DateInterval(start_time='2015-01-01 14:00:00', end_time='2015-01-01 17:00:00'),
             DateInterval(start_time='2015-01-01 15:00:00', end_time='2015-01-01 18:00:00'),
             DateInterval(start_time='2015-01-01 20:00:00', end_time='2015-01-01 22:00:00'),
             DateInterval(start_time='2015-01-01 20:00:00', end_time='2015-01-01 22:00:00')
             ]

(在这个示例列表中,开始日期和结束日期总是均匀地落在一小时上。但是,它们可以落在任何一秒上(或者毫秒)。在搜索了有关重叠间隔的stackoverflow问题的详尽列表后,我发现间隔树不适用于日期间隔)。

我的轻度优化蛮力方法由三个任务组成

  1. 识别所有非唯一的间隔集合,其中每个集合中至少有一个间隔与该集合中的所有其他间隔重叠

1.

下面通过简单地将间隔列表中的每个间隔与所有其他间隔进行比较,查找每个集合中只有一个间隔与该集合中的其他间隔重叠的所有非唯一集合。它假定间隔列表按日期-时间升序排序,从而启用中断优化

def search(intervals, start_date, end_date):
    results = []
    for interval in intervals:
        if end_date >= interval.start_time:
            if start_date <= interval.end_time:
                results.append(interval)
        else:
            break # This assumes intervals are sorted by date time ascending

search是这样使用的:

brute_overlaps = []
for interval in intervals:
    brute_overlaps.append(search(intervals, interval.start_time, interval.end_time))

2.

以下内容删除了集合列表:

def uniq(l):
    last = object()
    for item in l:
        if item == last:
            continue
        yield item
        last = item

def sort_and_deduplicate(l):
    return list(uniq(sorted(l, reverse=True)))

3.

下面通过简单地比较集合中的每个间隔和该集合中的每个其他间隔,找到每个集合中的每个间隔与该集合中的所有其他间隔重叠的所有集合:

def all_overlap(overlaps):
    results = []
    for overlap in overlaps:
        is_overlap = True
        for interval in overlap:
            for other_interval in [o for o in overlap if o != interval]:
                if not (interval.end_time >= other_interval.start_time and interval.start_time <= other_interval.end_time):
                    is_overlap = False
                    break # If one interval fails
             else:        # break out of
                 continue # both inner for loops
             break        # and try next overlap

        if is_overlap: # all intervals in this overlap set overlap with each other
            results.append(overlap)
    return results

共有1个答案

皇甫喜
2023-03-14

一组间隔,其中每个间隔必须与集合中的每个间隔重叠,将有一个共同点,即它们都重叠。相反,查询一个点上的所有间隔将得到一组相互重叠的间隔。

考虑到这一点,你的问题就变成了“通过改变我查询的点,我可以得到什么不同的间隔子集?”。获取所有这些不同子集的一个简单方法是找到重叠间隔必须改变的事件的位置,并在每对事件之间的一点进行查询。

对于间隔,事件对应于任何间隔开始或任何间隔结束。因此,您只需从左到右扫描开始和停止的时间间隔,同时跟踪已开始但未结束的时间间隔集。这就给出了所有相互重叠的最大子集。

在伪代码中。。。

maximalMutuallyOverlappingSubsets =
    intervals
    .flatMap(e => [(e.start, e, true),
                   (e.end, e, false)])
    .sortedBy(e => e[0]).
    .scan({}, (prevSet, (x, interval, add)) =>
        if add
        then prevSet + {interval}
        else prevSet - {interval})
    .distinct() - {{}}

O(n lg n)时间内运行,排序是最昂贵的步骤。

如果您不熟悉,flatMap会将列表中的每个项投影到结果集合中,然后将所有这些结果集合的项连接在一起。扫描从给定的累加器开始,并不断将下一项与给定函数组合到累加器中,同时产生中间结果。

 类似资料:
  • 假设我有一个这样的范围列表 现在我想找到一个范围,比如。我的算法应该给我这个范围的所有范围。例如,这个的输出应该是 <代码>输出-[1,3]、[2,5]、[4,6]、[8,10] 我该如何着手解决这个问题? PS:我知道段树可能会有所帮助。我可以在其中构建树来存储间隔并查询位于间隔内的Point,但如何在给定间隔的情况下获取所有间隔。

  • 这与寻找重叠的间隔有关。给定一个间隔列表(间隔树),我知道如何做到这一点。我有一个间隔列表。例如, 结果应该是 [2,3], [7,8] 我需要做的是找到所有列表中常见的间隔列表。 我认为这个问题类似于合并列表。问题是我无法应用列表的成对合并。应用此方法可能会导致丢失重叠间隔。因此,我需要将所有列表合并在一起,一次考虑所有列表(而不是成对)。 我可以使用间隔树。将每个列表中的第一个间隔插入间隔树并

  • 问题内容: 我正在编写一个利用JavaScript超时和间隔来更新页面的应用程序。有没有办法查看设置了多少间隔?我想确保不会因设置数百个间隔而意外杀死浏览器。 这甚至是个问题吗? 问题答案: 我不认为有一种方法来枚举活动的定时器,但是你可以重写,并与自己的实现其做一些跟踪,然后调用原件替换它们。 当然,您不一定总是调用,但这至少可以为您提供某种方式来跟踪运行时发生的情况。

  • 间隔有开始和结束时间。间隔可能重叠。可能有几个包含时间t的间隔。只返回其中一个就可以了。 这是一个面试问题。我能够解决这个问题,方法是根据结束对间隔进行排序,根据开始对另一个时间进行排序,并取具有匹配开始和结束的间隔的交点。显然有更多优化的解决方案。 这里有一个例子:[1,5][2,10][3,6][2,9],目标是8。在这种情况下,[2,10]和[2,9]中的任何一个都是正确答案。 我想问题的关

  • 问题内容: 我有下表,其中包含每15分钟从几个不同的设备读取的值: 我想在表中找到每个月在给定月份中没有条目的所有设备的所有差距。对于上表,结果应该是这样的: 该表大约有35000台设备和1亿个条目。 这是我尝试过的;它很慢,但是返回我需要的。但是,除了速度之外,还有另一个问题:它只能找到在给定月份设备的最后一个条目之前丢失的时间间隔;之后的所有内容都将被忽略,因此有可能会错过额外的缺失值间隔。

  • 问题内容: 问题:给定一组任意时间间隔的时间,将所有重叠的时间间隔合并为一个,然后输出结果,该结果应该只有互斥的时间间隔。为了简单起见,将间隔表示为整数对。例如,让给定的间隔集为{{1,3},{2,4},{5,7},{6,8}}。间隔{1,3}和{2,4}彼此重叠,因此应将它们合并并成为{1,4}。同样,{5,7}和{6,8}应该合并并成为{5,8} 编写一个函数,该函数为给定间隔集生成合并间隔集