我正在尝试回答关于在线裁判的问题,但我一直遇到时间限制问题。该问题的主要思想是求解列表的总和减去该列表中的子列表的总和。可以看到完整的问题规范 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次循环?
答案 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]
比获取切片的总和更快。