【发布时间】:2015-03-16 09:13:57
【问题描述】:
我正在实施和测试this SO question 的答案 -
给定一个整数数组,找出数组中所有有序元素对的数量,其和位于给定范围 [a,b]
The answer with the most upvotes(目前)仅提供算法的文本描述,应该是 O(NlogN):
对数组排序... 对于数组中的每个元素 x: 考虑元素之后的数组切片。 在这个数组切片上进行二分搜索[a - x],称之为y0。如果未找到完全匹配,则将大于 [a - x] 的最接近的匹配视为 y0。 只要 x + y
我的实现:
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 与 N T / NlogN vs N - 一位评论者认为这不应该产生线性图 - 但确实如此。 T vs NlogN - 如果复杂度是 NlogN,我认为这应该是线性的,但事实并非如此。
【问题讨论】:
-
你为什么要切片?
bisect函数采用下限和上限,因此您可以完全避免创建一个新列表(该列表累积需要 2N 次操作,乘以 N 步,使您的代码为 N^2,尽管内部循环使用快速 C 代码)。跨度> -
@MartijnPieters 不幸的是,为了清楚起见,我试图保持简单,然后看不到该决定的后果。
-
还有一个更紧凑的实现,使用
sum()来说明:gist.github.com/mjpieters/88c039207be8353e8620