找到c使得和(x + c)超过正数= K.

时间:2014-08-15 01:04:04

标签: python algorithm numpy scipy

假设我在Python中有一个带有正值和负值的1D数组x,例如:

x = random.rand(10) * 10

对于K的给定值,我希望找到偏移c,使得总和 数组y = x + c的元素等于K

如何有效地解决这个问题?

2 个答案:

答案 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+1c减少,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),因为它由初始排序控制。