我得到两个包含自然数A和B的数组,我需要找到最小化和A [i] * | B [i] -B [k] |的索引k。从i = 0到n-1。 (两个数组的长度相同) 它在O(n ^ 2)中显然很容易,我只计算0和n-1之间所有k的所有和,但我需要更好的运行时复杂度。
有什么想法吗?谢谢!
答案 0 :(得分:8)
您可以在时间O(nlogn)中执行此操作,首先根据B中的值对两个数组进行排序,然后执行单次扫描。
一旦数组被排序,则如果i> k则B [i]> = B [k]并且如果i <= k则B [i] <= B [k],因此可以将该和重写为:
sum A[i] * abs(B[i]-B[k]) = sum A[i]*(B[i]-B[k]) for i=k..n-1
+ sum A[i]*(B[k]-B[i]) for i=0..k-1
= sum A[i]*B[i] for i=k..n-1
- B[k] * sum A[i] for i=k..n-1
+ B[k] * sum A[i] for i = 0..k-1
- sum A[i]*B[i] for i = 0..k-1
您可以预先计算时间O(n)中的所有总和,然后让您在O(n)中的每个位置评估目标总和,并选择k的值,以获得最佳分数。
答案 1 :(得分:5)
我相信我能做到的就是O(n log n)。
首先,对B
数组进行排序,将相同的排列应用于A
数组(并记住排列)。这是O(n log n)部分。由于我们对所有i进行求和,因此对A和B数组应用相同的置换不会改变最小值。
使用排序的B
数组,算法的其余部分实际上是O(n)。
对于每个k,定义一个数组C k [i] = | B [i] - B [k] |
(注意:我们实际上不会构造C k ...我们只是将它用作概念以便于推理。)
观察我们试图最小化的数量(超过k)是A [i] * C k [i]的总和。让我们继续,给它一个名字:
定义:S k =ΣA[i] * C k [i]
现在,对于任何特定的k,C k 是什么样的?
嗯,C k [k] = 0,显然。
更有趣的是,由于B数组已经排序,我们可以摆脱绝对值符号:
让我们再定义两件事。
定义:T k =ΣA[i] 0 <= i
定义:U k =ΣA[i]对于k <我&lt; Ñ
(即,T k 是A的第一个k-1个元素的总和.U k 是除A的前k个元素之外的所有元素的总和。)
关键观察:给定S k ,T k 和U k ,我们可以计算S k + 1 < / sub>,T k + 1 ,并且U k + 1 在恒定时间内。怎么样?
T和U很容易。
问题是,我们如何从S k 到S k + 1 ?
当我们转到C k + 1 时,考虑C k 会发生什么。我们简单地将B [k + 1] -B [k]添加到从0到k的C的每个元素,并且我们从C的每个元素中减去相同的量,从k + 1到n(证明这一点)。这意味着我们只需要添加T k *(B [k + 1] - B [k])并减去U k *(B [k + 1] - B [k])从S k 到S k + 1 。
代数... S k 的前k个项只是A [i] *(B [k] - B [i])的0到k-1之和。 / p>
S k + 1 的前k项是A [i] *(B [k + 1] - B [i])
这些之间的差异是(A [i] *(B [k + 1] - B [i]) - (A [i] *(B [k])的从0到k-1的和。 - B [i]))。分解A [i]项并取消B [i]项以得到A [i] *(B [k + 1] - B [0]的0到k-1之和k]),它只是T k *(B [k + 1] - B [k])。
类似于S k 的最后一个n-k-1项。
因为我们可以在线性时间内计算S 0 ,T 0 和U 0 ,我们可以从S 开始k 到S k + 1 在恒定时间内,我们可以计算线性时间内的所有S k 。所以,记住最小的,你就完成了。
使用排序排列的倒数来获取原始数组的k
。
答案 2 :(得分:3)
这是O(NlogN)解决方案。 示例
A 6 2 5 10 3 8 7
B 1 5 4 3 6 9 7
1)首先将两个数组排序为增加B的顺序.A&#39; s元素仅与B绑定。 排序后,我们得到
A 6 10 5 2 3 7
B 1 3 4 5 6 7
因为B现在正在按顺序排列。我们有
n-1
sum A[i]|B[i]-B[k]|
i=0
k-1 n-1
=sum A[i](B[k]-B[i])+ sum A[i](B[k]-B[i])
i=0 i=k+1
k-1 n-1 k-1 n-1
=B[k](sum A[i] -sum A[i]) - (sum A[i]B[i]- sum A[i]B[i])
i=0 i=k+1 i=0 i=k+1
2)我们计算数组A的前缀和sumA = 0 6 16 21 23 26 33
i=e
With sumA sum A[i] can be calcuated in O(1) time for any s and e.
i=s
出于同样的原因,我们可以计算A [i] B [i]的前缀和。
因此,对于每个k,要检查其值,只需要O(1)时间。
总时间复杂度为O(NlogN)+O(N).