我有一个问题,一个OK-ish解决方案。我希望那里有更好的解决方案。
问题
我有一个大约有200,000个整数的数组。给定两个索引i1和i2,我需要计算i1和i2之间所有元素的总和。数组中的每个整数都介于1和4之间。例如:
a = [1, 3, 2, 4, 3, 2, 4, 1];
subsection_sum(a, 0, 3); // returns 6: (1 + 3 + 2)
此操作将执行大约200,000次,因此需要非常快。 for循环中的一个简单计数器是O(n),而且太慢了。在构建之后,阵列永远不会被修改,因此可以进行相对昂贵的预处理阶段。
到目前为止我的最佳解决方案
此算法适用于O(log n)时间:
首先用零填充原始数组,直到其长度为2的幂。接下来,将数组拆分为两个相等的部分并存储每个的总和。然后将数组拆分为四分之一并存储每个数组的总和。然后是八分之一。继续这样做,直到数组被分成2个元素长的部分。对于上面的8元素数组,这需要两个步骤:
halves = [(a[0] + a[1] + a[2] + a[3]), (a[4] + a[5] + a[6] + a[7])]
quarters = [(a[0] + a[1]), (a[2] + a[3]), (a[4] + a[5]), (a[6] + a[7])]
然后给出两个索引,现在可以在O(log n)时间内计算subsection_sum。例如,subsection_sum(a,2,7)== quarters [1] + halfves [1]。
答案 0 :(得分:14)
引入包含累积和的辅助数组。也就是说,辅助数组的元素i
具有原始数组的元素0到i
的总和。然后,子阵列总和只是辅助阵列中两个元素的差异。这将以恒定的时间O(1)
给出结果。
这取决于问题中给出的subsection_sum
函数的不变量:
subsection_sum(a, 0, i2) = subsection_sum(a, 0, i1) + subsection_sum(a, i1, i2)
我假设i1 <= i2
。重新安排,我们有:
subsection_sum(a, i1, i2) = subsection_sum(a, 0, i2) - subsection_sum(a, 0, i1)
请注意,右侧的总和均来自0
。可以将辅助数组视为缓存所有subsection_sum(a, 0, i)
的零i
之和的值。
答案 1 :(得分:3)
如果您能够支付O(n)
额外存储空间,则可以创建一个查找表,其i
元素是索引0
到i
(包括{,1}}的元素之和)在输入数组中。在伪代码中:
def computeLookupTable(arr):
let n = arr.length
let lookupTable = new Array()
lookupTable[0] = arr[0]
for i=1 to n:
lookupTable[i] = arr[i] + lookupTable[i-1]
return lookupTable
然后你可以使用这个表来计算array
和i1
之间i2
之间所有元素的总和。
lookupTable[i2] - lookupTable[i1]
需要一段时间。