用以下方法对数组中的元素求和的有效方法是什么
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,这将非常耗时。
如果查询集随每个k
而更改,那么您不能比在O(n)中做得更好。您唯一的优化选项是使用多个线程(每个线程对数组的某个区域求和),或者至少确保编译器正确地向量化您的循环(或者使用内部函数手动编写向量化版本)。
但若查询集是固定的,并且只更改了k
,那个么您可以使用以下优化在O(logn)中执行操作。
预处理数组。对于所有k
,此操作仅执行一次:
- 对元素排序
- 制作另一个包含部分和的相同长度的数组
例如:
inputArray: 5 1 3 8 7
sortedArray: 1 3 5 7 8
partialSums: 1 4 9 16 24
现在,当给出新的k
时,您需要执行以下步骤:
- 在
sortedArray
中对给定的k
进行二进制搜索——返回最大元素<=的索引k
- 结果为
partialSums[i] + (partialSums.length - i) * k
如果可以对数组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)
,但我认为它对您的情况没有用处。
参考
- std::sort()
- std::partial_sum()
- std::lower_bound()
你所做的似乎绝对不错。除非这真的是非常关键的时间(也就是说,客户抱怨你的应用程序太慢,你测量了它,而这个功能就是问题所在,在这种情况下,你可以尝试一些不可移植的矢量指令,例如)。
通常,你可以从更高的层面来看待事情,从而提高效率。例如,如果我写
for (n = 0; n < 1000000; ++n)
printf ("%lldn", sum (100));
那么这将需要非常长的时间(增加5万亿),而且可以更快地完成。如果一次更改数组A的一个元素,并且每次都重新计算sum,也是如此。
假设数组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来处理它。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用192/256位整数求和无符号64位整数向量的点积的最快方法
- 找到所有与自己求和的数字X的快速方法,去掉一个数字得到N
- 在高通六边形处理器的word32上执行水平求和的最快方法是什么
- 使用 C++17 或更高版本对向量中的元素对求和的最'functional'方法?
- 水平求和SSE无符号字节矢量的最快方法
- 用以下方法对数组中的元素求和的有效方法是什么
- 通过调用c++中向量中对象的方法来求和值
- 将特定数字求和以获得100的不同方法
- 用STD方法对两个级数求和