为什么我的实施O(NlogN)?

时间:2015-01-18 02:01:51

标签: python algorithm

我正在实施和测试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 vs N T / NlogN与N - 一位评论者认为这不应该产生线性图 - 但确实如此。 T / NlogN vs N T vs NlogN - 如果复杂性是NlogN,我认为这应该是线性的,但事实并非如此。 T vs NlogN

1 个答案:

答案 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.bisectlohi参数。