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

时间:2016-04-20 12:04:00

标签: c++ arrays data-structures

假设您有一个 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 (&lt; = 100000)查询,并且每次都给出了不同的 k ,那么它就变得非常耗时。

4 个答案:

答案 0 :(得分:3)

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

这个想法是:

  • 计算少于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),但我不认为它对你的情况有用。

<强>参考

答案 1 :(得分:3)

如果一组查询随每个k而变化,那么你不能比O(n)更好。您优化的唯一选择是使用多个线程(每个线程对数组的某个区域求和)或至少确保您的循环由编译器正确地向量化(或使用内在函数手动编写向量化版本)。

但是如果修复了一组查询并且只更改了k,则可以使用以下优化在O(log n)中进行。

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

  1. 排序元素
  2. 制作另一个长度相同的数组,其中包含partial sums
  3. 例如:

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

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

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

答案 2 :(得分:0)

你做的事似乎绝对没问题。除非这确实是绝对时间关键的(即客户抱怨你的应用程序太慢并且你测量它,并且这个功能是问题,在这种情况下你可以尝试一些非便携式矢量指令,例如)。

通常,您可以通过从更高级别查看它们来更有效地执行操作。例如,如果我写

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

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

答案 3 :(得分:0)

假设数组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来处理它。