繁体   English   中英

确定所有间隔是否重叠

[英]Deciding if all intervals are overlapping

我正在做一个问题,n 人站在一条线上,每个人都知道自己的 position 和速度。 我被要求找到让所有人 go 到任何地点的最短时间。

基本上我正在做的是使用二进制搜索找到最短时间,并且在那个时间间隔内让每个人与 go 的最远距离。 如果所有区间重叠,有一个点大家可以go到。

我对这个问题有一个解决方案,但是我的错误解决方案超过了时间限制来找到间隔。 我目前的解决方案运行速度太慢,我希望得到更好的解决方案。

我的代码:

    people = int(input())
    peoplel = [list(map(int, input().split())) for _ in range(people)] # first item in people[i] is the position of each person, the second item is the speed of each person
    def good(time):
        return checkoverlap([[i[0] - time *i[1], i[0] + time * i[1]] for i in peoplel])
        # first item,second item = the range of distance a person can go to 
 

    def checkoverlap(l):
        for i in range(len(l) - 1):
            seg1 = l[i]
            for i1 in range(i + 1, len(l)):
                seg2 = l[i1]
                if seg2[0] <= seg1[0] <= seg2[1] or seg1[0] <= seg2[0] <= seg1[1]:
                    continue
                elif seg2[0] <= seg1[1] <= seg2[1] or seg1[0] <= seg2[1] <= seg1[1]:
                    continue
                return False
        return True

(这是我第一次问问题,所以请告诉我任何错误的地方)

一个简单的 go 线性

在我完成答案后不久,我发现了一个简化,它消除了排序的需要,从而使我们能够进一步降低查找所有间隔是否与O(N)重叠的复杂性。

如果我们查看初始排序之后正在执行的步骤,我们可以看到我们基本上是在检查

if max(lower_bounds) < min(upper_bounds):
    return True
else:
    return False

由于minmax都是线性的,不需要排序,我们可以通过以下方式简化算法:

  • 创建一个下限数组 - 一次通过。
  • 创建一个上限数组 - 一次通过。
  • 进行我上面提到的比较 - 两次通过新的 arrays。

所有这些都可以一次性完成以进一步优化(并防止一些不必要的 memory 分配),但是这对于解释的目的来说更清楚。

由于关于正确性和时序的推理是在上一次迭代中完成的,因此我将跳过它并保留下面的部分,因为它很好地展示了优化背后的思考过程。

一种统治他们的方式

免责声明:本部分在时间上已被上述部分淘汰。 但是,由于它实际上使我能够找出线性解决方案,因此我将其保留在这里。

正如标题所说,排序是一种相当直接的方法。 它将需要一些不同的数据结构 - 而不是将每个间隔保存为(min, max)我选择将每个间隔保存为(min, index), (max, index) 这使我可以按minmax对它们进行排序。 接下来是对排序数组的一次线性传递。 我们还创建了一个 False 值的辅助数组。 这些表示在开始时所有区间都是闭合的。
现在是对数组的传递:

  • 由于数组是排序的,我们首先遇到每个区间的min 在这种情况下,我们增加openInterval计数器和间隔本身的True值。 间隔现在是开放的——直到我们关闭间隔,这个人才能到达聚会——我们在他(或她)的范围内。
  • 我们沿阵列 go。 只要我们打开间隔,一切都很好,如果我们设法打开所有间隔,我们就有了聚会的目的地,所有的社交距离都会崩溃。 如果发生这种情况,我们返回True
  • 如果我们关闭任何间隔,我们就会发现我们的破坏者不能再成功了。 (或者我们可以讨论,当有人已经到 go 时,派对破坏者是那些还没来的人)。 我们返回False

初始排序导致的复杂度为O(Nlog(N)) ,因为 pass 本身本质上是线性的。 这比由“成对检查所有间隔”方法引起的原始 O(n^2) 好很多。

编码:

import numpy as np
import cProfile, pstats, io

#random data for a speed test. Not that useful for checking the correctness though.
testSize = 10000
x = np.random.randint(0, 10000, testSize)
y = np.random.randint(1, 100, testSize)
peopleTest = [x for x in zip(x, y)]

#Just a basic example to help with the reasoning about the correctness
peoplel = [(1, 2), (3, 1), (8, 1)]
# first item in people[i] is the position of each person, the second item is the speed of each person


def checkIntervals(people, time):
    a = [(x[0] - x[1] * time, idx) for idx, x in enumerate(people)]
    b = [(x[0] + x[1] * time, idx) for idx, x in enumerate(people)]
    checks = [False for x in range(len(people))]
    openCount = 0
    intervals = [x for x in sorted(a + b, key=lambda x: x[0])]
    for i in intervals:
        if not checks[i[1]]:
            checks[i[1]] = True
            openCount += 1
            if openCount == len(people):
                return True
        else:
            return False

    print(intervals)



def good(time, people):
    return checkoverlap([[i[0] - time * i[1], i[0] + time * i[1]] for i in people])
    # first item,second item = the range of distance a person can go to


def checkoverlap(l):
    for i in range(len(l) - 1):
        seg1 = l[i]
        for i1 in range(i + 1, len(l)):
            seg2 = l[i1]
            if seg2[0] <= seg1[0] <= seg2[1] or seg1[0] <= seg2[0] <= seg1[1]:
                continue
            elif seg2[0] <= seg1[1] <= seg2[1] or seg1[0] <= seg2[1] <= seg1[1]:
                continue
            return False
    return True


pr = cProfile.Profile()
pr.enable()

print(checkIntervals(peopleTest, 10000))

print(good(10000, peopleTest))

pr.disable()
s = io.StringIO()
sortby = "cumulative"
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print(s.getvalue())

具有 10K 随机值的通过测试数组的分析统计数据:

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.001    0.001    8.933    8.933 (good)
    1    8.925    8.925    8.926    8.926 (checkoverlap)
    1    0.003    0.003    0.023    0.023 (checkIntervals)
    1    0.008    0.008    0.010    0.010 {built-in method builtins.sorted}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM