求一个数组中的数字的和

Summing up numbers in an array

本文关键字:数字 数组 一个      更新时间:2023-10-16

假设我有一个由N个非负整数组成的数组,每个非负整数都可以很大(0->10000)。让我们也假设N可以非常大(约100000000)。

对于数组[a0 a1…an-1],我想写一个函数,它返回整个数组的(-2)^ai的和。我想要O(n*log(n))的时间复杂度和O(n)的空间。

例如,取[1 2 3]--这将返回(-2)^1+(-2)^2+(-2)^ 3=-6另一个限制是,对于超过100000000的答案,函数应该返回-1;

一个天真(但错误)的解决方案如下:

int solve(vector<int> &A) {
int answer = 0;
for (auto iter = A.begin(); iter != A.end(); ++iter) {
answer += pow(-2, *iter);
}
return (answer <= 1e8) ? answer : -1;
}

如果值>31,则b/c应答将溢出(假设本机有符号整数大小为4字节)。对于数组中大于63的值,使用longs也不起作用。

我能想到的一个高级解决方案是使用std::sort对数组进行排序,然后遍历它。对于数组中大于31的值,我们从数组中的值中减去31的倍数。这是可以接受的b/c我们处理的是指数和。我很好奇这个问题是否有已知的O(n*log(n))复杂性,O(n)空间解。

注意,(-2)^K有不同的简单二进制表示:对于偶数K是..00001000..,对于奇数K(2的补码)是..1111110000..

因此,您可以创建数组(int或boolean),用于以二进制表示形式累积总和。它的长度应该通过数组的最大值来确定(开销取决于N-大约Log2(N)个单元)。

然后遍历数组,将当前数字的二进制表示形式添加到累加器中。阵列A=[2,3,4]示例

value(K)     binary(-2)^K   accum
00000000    
2            100           00000100
3            11111000      11111100 
4            00010000      00001100 

每个加法运算需要Max(A)+Log2(N)基本运算

可能的小型优化-对输入数组进行排序,并对重复值进行分组。例如,如果数组包含4的8个值,则可以很容易地在单移位操作中取8*(-2)^4= 10000 << 3 = 10000000,而不需要7个加法操作。

一个想法。。。

您的功能回答2个问题:

1) 结果是否符合100M限制2) 低于100M 的项目总数是多少

如果1)不满足,则不必计算后者,因此最终计数可以不太关心某个值是否符合int。

为了使事情更容易,我们可以使用计数排序和总和计数。让我们使数组计数,它将保持2^(i)的乘数,因此最终的和将是sum(counts[i]*2^i)。并不是说计数不使用符号触发器,我们在填充时必须放置适当的符号。

现在我们可以做计数减少数组了。注意,如果计数[i]>2,则修改如下的数组的总和将相同:

  • 计数[i]-2
  • 计数[i+1]+1

同样适用于负号。因此,在一个从0到最大计数的循环中,我们可以减少计数中的值,每个值只留下0和1/-1。

如您所知,2^N索引的值大于在0..2^N-2值中累积至少2次的任何值的总和。所以,若你们的最高指数(减少后)大于28(2^28=268435456),那个么结果将不适合100000000。

现在,如果1)是pased,您知道最终和临时结果不大于268435456,所以它将适合int类型,所以只需计算并再次检查最终结果。