我有一个排序数组X [k]。 现在我想找到
我试过这个
int ans=0;
for(int i=1;i<=k;i++)
{
for(int j=i+1;j<=k;j++)
{
ans+=abs(X[i]-X[j]);
}
}
我使用上面的解决方案得到了正确的答案,但是没有优化,在某些情况下超出了时间限制。 是否有任何算法以最小的复杂性实现这一点?
答案 0 :(得分:5)
我们需要计算:Sigma[i] Sigma[j>i] abs(Xi-Xj)
。 (指数i,j假设在1到k之间)。
因为数组是排序的,所以对于j> i,Xj> = Xi。这允许你摆脱abs
,以便你有:
Sigma[i] Sigma[j>i] (Xj - Xi)
这可以分为两个总和:
Sigma[i] Sigma[j>i] Xj - Sigma[i] Sigma[j>i] Xi
对于特定的j
,Xj
出现在第一笔金额中的次数是多少? X2出现一次(仅适用于i = 1且j = 2),X3出现两次(i = 1,j = 3且i = 2,j = 3)等。通常,Xj
出现{{1 }},所以它为总和贡献j-1
(假设基于1的索引)。
以同样的方式,(j-1)Xj
在第二笔金额中显示Xi
次,因此会向总数提供(k-i)
。
这给出了结果:(k-i)Xi
。这可以简化为:
Sigma[j](j-1)Xj - Sigma[i](k-i)Xi
这是用O(n)计算的,而不是O(n ^ 2)的平凡算法。
答案 1 :(得分:1)
假设此处sorted
表示
对于任何1≤i≤j≤N,有X i ≤X j 。
并将您的计算目标表示为F
令F(X 1..N )=Σ1≤i<1。 j≤N | X i - X j |
然后我们
F(X 1..N )
= F(X 2..N )+Σ1≤i≤N | X i - X 1 |
= F(X 3..N )+Σ2≤i≤N | X i - X 2 | +Σ1≤i≤N | X i - X 1 |
= F(X 4..N )+ ...
注意
Σk≤i≤N | X i - X k |
=(N - k)×(X k + 1 - X k )+Σ k +1≤i≤N | X i - X k + 1 |
所以我们有以下迭代来计算总和:
/*
* assuming here the data type int is suitable for holding the result
* N is the array length, X is the sorted array
*/
int sorted_sub_sum(int N, const int *X)
{
int ret = 0;
int tmp_sum = 0;
int i;
for (i = 0; i < N; i++)
tmp_sum += X[i] - X[0];
for (i = 0; i < N - 1; i++)
{
ret += tmp_sum;
tmp_sum -= (N - i - 1) * (X[i + 1] - X[i]);
}
return ret;
}
我对这段代码做了一些简单的测试(比如数组{1,2,4,9}和{1,2,4,9,17})。如果您发现任何错误,请告诉我。
已编辑:我没有仔细阅读OP的定义,在我的回答N
中表示数组长度与原始问题中的k
一样。很抱歉给您带来不便。
答案 2 :(得分:0)
您可以通过O(n)
时间非常简单的方式执行此操作,并且如其他答案中所述,abs
函数是多余的:
int ans = 0;
for (int i = 0; i < X.lengh; i++)
ans += ((X.length - i) * (i)) * (X[i] - X[i-1]);
这个方法基于X[i] - X[i-2] = 2(X[i] - X[i-1]) - (X[i-1] - X[i-2])
的事实,这允许你打破每个计算并计算数组中两个相邻数字相减的总次数。
答案 3 :(得分:-1)
我们可以摆脱abs(阵列被排序)然后在结果中x_1出现(k-1)次为负,X_2出现1次正面而k-2次负面意味着我们完全计算它k- 3次负数和.... x_(k-1)出现k-3次正数,x_k出现k-1次正数,因此我们得到以下简化求和:
int coef = 1-k;
int sum = 0;
for(int i=0;i<k;i++)
{
sum += coef * x[i];
coef += 2;
}
在代码中,我认为数组是基于零的索引,x [0]等于我的描述中的x_1。