繁体   English   中英

用以下方法总结数组元素的有效方法是什么?

[英]Whats the efficient way to sum up the elements of an array in following way?

假设给定一个n大小的数组A和一个整数k
现在您必须遵循以下功能:

long long sum(int k)
{
    long long sum=0;
    for(int i=0;i<n;i++){
        sum+=min(A[i],k);
    }
    return sum;
}

最有效的求和方式是什么?

编辑:如果给我m (<= 100000)个查询,并且每次给出不同的k ,它将变得非常耗时。

如果可以对数组A[i]排序并准备一次辅助数组, 可以做得更好。

这个想法是:

  • 计算小于k项目k ,然后通过以下公式计算等效和: count*k
  • 准备一个辅助数组,它将直接为您提供优于k的项的总和

制备

步骤1:对数组排序

std::sort(begin(A), end(A));

步骤2:准备一个辅助数组

std::vector<long long> p_sums(A.size());
std::partial_sum(rbegin(A), rend(A), begin(p_sums));

询问

long long query(int k) {
  // first skip all items whose value is below k strictly
  auto it = std::lower_bound(begin(A), end(A), k);

  // compute the distance (number of items skipped)
  auto index = std::distance(begin(A), it);

  // do the sum
  long long result = index*k + p_sums[index];
  return result;
}

查询的复杂度为: O(log(N))其中N是数组A的长度。

准备的复杂度为: O(N*log(N)) 我们可以将基数排序为O(N) ,但我认为这对您没有用。

参考

如果查询集随着k变化而变化,那么您做的比O(n)更好。 优化的唯一选择是使用多个线程(每个线程对数组的某个区域求和),或者至少确保编译器对循环进行了正确的矢量化处理(或使用内部函数手动编写矢量化的版本)。

但是,如果查询集是固定的,并且只更改了k ,则可以使用以下优化在O(log n)中进行操作。

预处理数组。 对于所有k s只能执行一次:

  1. 排序元素
  2. 制作另一个相同长度的数组,其中包含部分和

例如:

inputArray: 5 1 3 8 7
sortedArray: 1 3 5 7 8
partialSums: 1 4 9 16 24

现在,当给定新的k时,您需要执行以下步骤:

  1. sortedArray给定k进行二进制搜索-返回最大元素<= k索引
  2. 结果为partialSums[i] + (partialSums.length - i) * k

您所做的事情似乎绝对不错。 除非这真的是绝对时间紧迫的(除非客户抱怨您的应用程序速度太慢而您测量了它,而这个功能就是问题所在,在这种情况下,您可以尝试一些不可移植的矢量指令)。

通常,您可以从更高的层次看待事情,从而更有效地做事。 例如,如果我写

for (n = 0; n < 1000000; ++n)
   printf ("%lld\n", sum (100));

那么这将花费很长的时间(增加一半的万亿),并且可以更快地完成。 如果一次更改数组A的一个元素,然后每次重新计算总和,则相同。

假设数组A的x个元素不大于k,集合B包含那些大于k的元素并属于A。

然后,函数sum(k)的结果等于

k * x + sum_b

,其中sum_b是属于B的元素之和。

您可以首先对数组A排序,然后计算数组pre_A,其中

pre_A[i] = pre_A[i - 1] + A[i] (i > 0),
        or 0 (i = 0);

然后对于每个查询k,在A上使用二进制搜索来找到不大于k的最大元素u。 假设u的索引是index_u,则sum(k)等于

 k * index_u + pre_A[n] - pre_A[index_u]

每个查询的时间复杂度为log(n)。

如果数组A可以动态更改,则可以使用BST进行处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM