优化列表范围中的数字总和

时间:2015-09-29 18:35:26

标签: python algorithm list for-loop

我正在尝试回答关于在线裁判的问题,但我一直遇到时间限制问题。该问题的主要思想是求解列表的总和减去该列表中的子列表的总和。可以看到完整的问题规范 here.

这是我的代码:

import sys
lists = sys.stdin.read().strip().split('\n')

showScores = map(int, lists[1].split())
maximum = sum(showScores)
loops = map(int, lists[0].split())[1]

for i in range(2, loops+2):
    subList = lists[i].split()
    print maximum - sum(showScores[int(subList[0])-1 : int(subList[1])])

有没有更好的算法来解决问题?我应该如何处理这个问题,考虑到我必须做多达500,000次循环?

2 个答案:

答案 0 :(得分:3)

您可以避免为每个查询调用sum。无论切片效率如何,您仍需要在当前设置下迭代该范围以计算其总和。因此,您需要优化算法,而不是代码。

如果你有:

S[i] = sum of the first i numbers
     = a[0] + a[1] + ... + a[i]

您可以在O(n)中计算:

S[i] = S[i - 1] + a[i]

如何使用O(1)

回答S中的每个查询

提示:如果您必须计算某个时间间隔[x, y]的总和,我们会使用:

S[y] = a[0] + a[1] + ... + a[x] + ... + a[y]
S[x] = a[0] + a[1] + ... + a[x - 1] + a[x]

答案 1 :(得分:2)

@IVlad在他的回答中提供了一个非常有用的提示,并且我将通过示例更进一步。任何时候你可以在循环之前预先计算值,循环执行得越快。在切片上运行sum()将每次为同一切片返回相同的值,因此预先计算循环之前的总和。

如果您生成了第一个a分数的总和列表,它将如下所示:

first = [0, 5, 11, 18, 26, 29, 33, 38, 44, 45, 47]

如果你还生成了最后b分数总和的列表,它将如下所示:

last = [47, 42, 36, 29, 21, 18, 14, 9, 3, 2, 0]

在你的循环中,你可以

print first[a-1] + last[b]

比获取切片的总和更快。