总结数组中的数字

时间:2017-01-23 04:40:43

标签: c++ arrays algorithm

假设我有一个N个非负整数的数组,每个非负整数可以非常大(0-> 100,000)。我们也假设N可以非常大(~100,000,000)。

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

例如,取[1 2 3] - 这将返回(-2)^ 1 +( - 2)^ 2 +( - 2)^ 3 = -6 另一个限制是,对于超过100,000,000的答案,函数应该返回-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;
    }

这不起作用b / c答案将溢出值&gt; 31(假设本机有符号整数大小为4个字节)。使用long也无法使b / c中断数组中大于63的值。

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

2 个答案:

答案 0 :(得分:1)

请注意,(-2)^K改变了简单的二进制表示形式:偶数K为..00001000..,奇数K为..1111110000..(2&#39; s补码)。

因此,您可以创建数组(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)基本操作

可能的迷你优化 - 对输入数组和组重复值进行排序。例如,如果数组包含8的值4,则可以在单班操作中轻松获取8*(-2)^4= 10000 << 3 = 10000000,而无需7次添加操作。

答案 1 :(得分:0)

一个想法......

您的功能回答了2个问题:

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

如果1)不满意,你不必计算后者,所以最终计数可以更少关心是否适合int。

为了简化操作,我们可以使用计数排序和总和计数。让数组计数将保持2 ^(i)的乘数,因此最终的总和将是sum(counts [i] * 2 ^ i)。不是计数不使用标志触发器,我们必须在填充时添加适当的标志。

现在我们可以减少计数数组。注意,如果计数[i]> 2,那么对于修改如下的数组,sum将是相同的:

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

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

如您所知,2 ^ N索引的值大于在0..2 ^ N-2值中累积的任何值的总和至少2次。因此,如果您的最高指数(减少后)大于28(2 ^ 28 = 268,435,456),那么结果将不适合100,000,000。

现在,如果1)是pase,你知道最终和临时结果不大于268,435,456,所以它将适合int类型,所以只需做数学并再次检查最终结果。