我正在实施和测试this SO question -
的答案给定一个整数数组,找到数组中所有有序元素对的数量,其总和位于给定范围[a,b]
The answer with the most upvotes(当前)仅提供应为O(NlogN)的算法的文本描述:
对数组进行排序.... 对于数组中的每个元素x: 考虑元素后面的数组切片。 在[a - x]的数组切片上进行二进制搜索,将其称为y0。如果未找到完全匹配,请将最接近的匹配大于[a - x]视为y0。 只要x + y <= b,就从y0向前输出所有元素(x,y)。 ...如果您只需要计算对数,可以在O(nlogn)中进行。修改上述算法,以便搜索[b - x](或下一个较小的元素)。
我的实施:
import bisect
def ani(arr, a, b):
# Sort the array (say in increasing order).
arr.sort()
count = 0
for ndx, x in enumerate(arr):
# Consider the array slice after the element
after = arr[ndx+1:]
# Do a binary search on this array slice for [a - x], call it y0
lower = a - x
y0 = bisect.bisect_left(after, lower)
# If you only need to count the number of pairs
# Modify the ... algorithm so [b - x] ... is also searched for
upper = b - x
y1 = bisect.bisect_right(after, upper)
count += y1 - y0
return count
当我绘制时间与N或N的某些函数时,我看到指数或N ^ 2响应。
# generate timings
T = list() # run-times
N = range(100, 10001, 100) # N
arr = [random.randint(-10, 10) for _ in xrange(1000000)]
print 'start'
start = time.time()
for n in N:
arr1 = arr[:n]
t = Timer('ani(arr1, 5, 16)', 'from __main__ import arr1, ani')
timing_loops = 100
T.append(t.timeit(timing_loops) / timing_loops)
我的实施不正确还是作者的说法不正确?
以下是一些数据图。
T vs N. T / NlogN与N - 一位评论者认为这不应该产生线性图 - 但确实如此。 T vs NlogN - 如果复杂性是NlogN,我认为这应该是线性的,但事实并非如此。
答案 0 :(得分:6)
如果没有别的,这是你的错误:
for ndx, x in enumerate(arr):
# Consider the array slice after the element
after = arr[ndx+1:]
arr[ndx+1:]
创建长度为len(arr) - ndx
的列表的副本,因此您的循环为O(n ^ 2)。
相反,请使用bisect.bisect
的lo
和hi
参数。