求出求和时的三元组总数小于给定阈值

时间:2014-10-08 20:55:37

标签: python arrays algorithm

所以我正在解决一些练习问题并且难以降低复杂性。我得到一组不同的整数a []和一个阈值T.我需要找到三元组ijk的数量,以便a[i] < a[j] < a[k]a[i] + a[j] + a[k] <= T。我已经使用以下python脚本从O(n^3)O(n^2 log n)了。我想知道我是否可以进一步优化这一点。

import sys
import bisect

first_line = sys.stdin.readline().strip().split(' ')
num_numbers = int(first_line[0])
threshold = int(first_line[1])
count = 0

if num_numbers < 3:
    print count
else:
    numbers = sys.stdin.readline().strip().split(' ')
    numbers = map(int, numbers)
    numbers.sort()

    for i in xrange(num_numbers - 2):
        for j in xrange(i+1, num_numbers - 1):
            k_1 = threshold - (numbers[i] + numbers[j])
            if k_1 < numbers[j]:
                break
            else:
                cross_thresh = bisect.bisect(numbers,k_1) - (j+1)
                if cross_thresh > 0:
                    count += cross_thresh

    print count

在上面的例子中,第一个输入行只提供了数字和阈值。下一行是完整列表。如果列表小于3,则不存在三元组,因此我们返回0.如果不是,我们读入整数的完整列表,对它们进行排序,然后按如下方式处理它们:我们遍历{的每个元素{1}}和i(这样i&lt; j)我们计算出不会破坏j的k的最高值。然后,我们找到列表中第一个违反此条件的元素的索引(i + j + k <= T),并获取j和s之间的所有元素,并将它们添加到计数中。对于列表中的30,000个元素,运行大约需要7分钟。有没有办法让它更快?

2 个答案:

答案 0 :(得分:3)

您正在为每个(i,j)对执行二进制搜索,以查找k的相应值。因此O(n^2 log(n))

我可以推荐一种最差情况时间复杂度为O(n^2)的算法。

假设列表从左到右排序,元素从1n编号。然后伪代码是:

for i = 1 to n - 2:
    j = i + 1
    find maximal k with binary search
    while j < k:
        j = j + 1
        find maximal k with linear search to the left, starting from last k position

O(n^2)而非O(n^3)的最差情况时间复杂度的原因是位置k单调递减。因此,即使使用线性扫描,您也不会为每个O(n)对花费(i,j)。相反,您需要花费O(n)的时间来为每个不同的k值扫描i

答案 1 :(得分:2)

用Python实现的

O(n^2)版本(基于wookie919的答案):

def triplets(N, T):
    N = sorted(N)
    result = 0

    for i in xrange(len(N)-2):
        k = len(N)-1
        for j in xrange(i+1, len(N)-1):
            while k>=0 and N[i]+N[j]+N[k]>T:
                k-=1
            result += max(k, j)-j

    return result

import random
sample = random.sample(xrange(1000000), 30000)
print triplets(sample, 500000)