这是我的问题。
给定一个整数数组和另一个整数k
,找到数组中每个元素和k
的差异总和。
例如,如果数组为2, 4, 6, 8, 10
且k
为3
Sum of difference
= abs(2 - 3) + abs(4-3) + abs(6 - 3) + abs(8 - 3) + abs(10 - 3)
= 1 + 1 + 3 + 5 + 7
= 17
阵列始终保持相同,最多可包含100000个元素,并且将测试100个不同的k值。 k可以是也可以不是数组的元素。这必须在1s或大约100M的操作中完成。我如何实现这一目标?
答案 0 :(得分:6)
如果添加费用O(log N)
的预处理步骤,则可以在O(N * log N)
中针对绝对差异的总和运行多个查询。
对数组进行排序,然后为数组存储中的每个项目排序小于或等于相应项目的所有数字的总和。这可以在O(N * log N)
中完成。现在你有一对看起来像这样的数组:
2 4 6 8 10 // <<== Original data
2 6 12 20 30 // <<== Partial sums
此外,存储数组中所有数字的总T
。
现在,您可以通过在原始数组上运行二进制搜索,并使用部分和数组中的和来计算答案来获得绝对差值的总和:减去目标左侧所有数字的总和{{1从目标时间k
左侧的数字计数开始,然后从数字右侧的总和中减去计数次数k
,并将这两个数字相加。可以通过从总k
中减去左边的部分和来计算数字右边的数字的部分和。
对于T
二分搜索,您可以定位k=3
。
答案 1 :(得分:5)
首先对数组进行排序,然后计算一个数组,该数组存储生成的有序数组的前缀之和。让我们表示这个数组p
,您可以在线性时间内计算p
,以便p[i] = a[0] + a[1] + ... a[i]
。现在有了这个数组,你可以不断复杂地回答问题是什么是元素a[x] + a[x+1] + .... +a[y]
的总和(即索引x
到y
)。要做到这一点,你只需计算p[y] - p[x-1]
(当x为1时要特别小心)。
现在回答类型的查询是什么是与k
的绝对差的总和,我们将问题分为两部分 - 大于k的数字和小于k的数字之和是什么。为了计算这些,请执行二分搜索以在已排序的a
中找到k的位置(表示idx
),并在a
之前计算idx
之前的值的总和1}}(表示s
)和idx
之后(表示S
)。现在,与k
的绝对差值之和为idx * k - s + S - (a.length - idx)* k
。这当然是伪代码,我所说的a.length是a
中的元素数。
执行线性预计算后,您将能够使用O(log(n))
回答查询。请注意,如果您计划执行多个查询,此方法才有意义。如果您只打算执行单个查询,则速度可能不会超过O(n)
。
答案 2 :(得分:1)
在&#34;比赛C ++&#34;中实施dasblinkenlight&#34;
完全如他所说。读取值,对它们进行排序,将累积的和存储在V [i] .second中,但是这里V [i]是累积的和,直到i-1(为了简化算法)。对于查询大于max(V)的情况,它还在V [n]中存储标记。
然后,对于每个查询,二进制搜索该值。在这种情况下,V[a].second
是小于query
的值的总和,V[n].second-V[a].second
是大于它的值的总和。
#include<iostream>
#include<algorithm>
#define pii pair<int, int>
using namespace std;
pii V[100001];
int main() {
int n;
while(cin >> n) {
for(int i=0; i<n; i++)
cin >> V[i].first;
sort(V, V+n);
V[0].second = 0;
for(int i=1; i<=n; i++)
V[i].second = V[i-1].first + V[i-1].second;
int k; cin >> k;
for(int i=0; i<k; i++) {
int query; cin >> query;
pii* res = upper_bound(V, V+n, pii(query, 0));
int a = res-V, b=n-(res-V);
int left = query*a-V[a].second;
int right = V[n].second-V[a].second-query*b;
cout << left+right << endl;
}
}
}
它假设一个文件格式如下:
5
10 2 8 4 6
2
3 5
然后,对于每个查询,它的答案如下:
17
13