[英]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
(这是我第一次问问题,所以请告诉我任何错误的地方)
在我完成答案后不久,我发现了一个简化,它消除了排序的需要,从而使我们能够进一步降低查找所有间隔是否与O(N)重叠的复杂性。
如果我们查看初始排序之后正在执行的步骤,我们可以看到我们基本上是在检查
if max(lower_bounds) < min(upper_bounds):
return True
else:
return False
由于min
和max
都是线性的,不需要排序,我们可以通过以下方式简化算法:
所有这些都可以一次性完成以进一步优化(并防止一些不必要的 memory 分配),但是这对于解释的目的来说更清楚。
由于关于正确性和时序的推理是在上一次迭代中完成的,因此我将跳过它并保留下面的部分,因为它很好地展示了优化背后的思考过程。
免责声明:本部分在时间上已被上述部分淘汰。 但是,由于它实际上使我能够找出线性解决方案,因此我将其保留在这里。
正如标题所说,排序是一种相当直接的方法。 它将需要一些不同的数据结构 - 而不是将每个间隔保存为(min, max)
我选择将每个间隔保存为(min, index), (max, index)
。 这使我可以按min
和max
对它们进行排序。 接下来是对排序数组的一次线性传递。 我们还创建了一个 False 值的辅助数组。 这些表示在开始时所有区间都是闭合的。
现在是对数组的传递:
min
。 在这种情况下,我们增加openInterval
计数器和间隔本身的True
值。 间隔现在是开放的——直到我们关闭间隔,这个人才能到达聚会——我们在他(或她)的范围内。初始排序导致的复杂度为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())
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.