所以我正在解决一些练习问题并且难以降低复杂性。我得到一组不同的整数a []和一个阈值T.我需要找到三元组i
,j
,k
的数量,以便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分钟。有没有办法让它更快?
答案 0 :(得分:3)
您正在为每个(i,j)
对执行二进制搜索,以查找k
的相应值。因此O(n^2 log(n))
。
我可以推荐一种最差情况时间复杂度为O(n^2)
的算法。
假设列表从左到右排序,元素从1
到n
编号。然后伪代码是:
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)
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)