假设我在Python中有一个带有正值和负值的1D数组x
,例如:
x = random.rand(10) * 10
对于K
的给定正值,我希望找到偏移c
,使得的总和 数组y = x + c
的元素等于K
。
如何有效地解决这个问题?
答案 0 :(得分:2)
二元搜索如何确定x + c
的哪些元素将对总和做出贡献,然后求解线性方程?此代码的运行时间为O(n log n),但只有O(log n)工作在Python中完成。运行时间可以通过更复杂的分区策略降低到O(n)。我不确定是否会带来实际的改善。
import numpy as np
def findthreshold(x, K):
x = np.sort(np.array(x))[::-1]
z = np.cumsum(np.array(x))
l = 0
u = x.size
while u - l > 1:
m = (l + u) // 2
if z[m] - (m + 1) * x[m] >= K:
u = m
else:
l = m
return (K - z[l]) / (l + 1)
def test():
x = np.random.rand(10)
K = np.random.rand() * x.size
c = findthreshold(x, K)
assert np.abs(K - np.sum(np.clip(x + c, 0, np.inf))) / K <= 1e-8
这是一个随机预期的O(n)变体。它更快(在我的机器上,对于大输入),但不是那么显着。请注意两个版本中的灾难性取消。
def findthreshold2(x, K):
sumincluded = 0
includedsize = 0
while x.size > 0:
pivot = x[np.random.randint(x.size)]
above = x[x > pivot]
if sumincluded + np.sum(above) - (includedsize + above.size) * pivot >= K:
x = above
else:
notbelow = x[x >= pivot]
sumincluded += np.sum(notbelow)
includedsize += notbelow.size
x = x[x < pivot]
return (K - sumincluded) / includedsize
答案 1 :(得分:0)
您可以按降序排序x
,循环x
并计算到目前为止所需的c
。如果下一个元素加c
为正,则应将其包含在总和中,以使c
变小。
请注意,可能存在没有解决方案的情况:如果您包含的元素最多为m
,则c
也应包含m+1
,但是当您包含时m+1
,c
减少,a[m+1]+c
可能会消极。
在伪代码中:
sortDescending(x)
i = 0, c = 0, sum = 0
while i < x.length and x[i] + c >= 0
sum += x[i]
c = (K - sum) / i
i++
if i == 0 or x[i-1] + c < 0
#no solution
运行时间显然是O(n log n)
,因为它由初始排序控制。