计算具有不同增量的循环迭代次数

时间:2012-05-09 09:06:57

标签: algorithm optimization

for (; i < limit; i += x) {
  x += 100;
}

是否有一个优雅的解决方案来计算ix而不使用循环结构?

我的想法:

我可以使用流行的高斯求和公式1+2+3+4+...+n = (n*(n+1))/2和二分搜索来降低从O(N)到O(log N)的复杂性。

Assume i = 0, x = 0 then:
i = 0*100 + 1*100 + 2*100 + 3*100 + ... + (n-1)*100 = ((n-1)*n)/2*100

if (i != 0 && x != 0) then:
i = i + x+0*100 + x+1*100 + x+2*100 + ... + x+(n-1)*100 = i+x*n + ((n-1)*n)/2*100

Thus (i < limit) = (i+x*n+((n-1)*n)/2*100 < limit)

现在使用某种二分搜索来找到满足上述不等式的最大n

if (i < limit)
    for (n = 1; i+x*n+((n-1)*n)/2*100 < limit; n -= j, n += 1)
        for (j = 1; i+x*n+((n-1)*n)/2*100 < limit; n += j, j += j);

现在我发现初始for循环的迭代次数nix可以使用以下方法计算:

i += x*n+((n-1)*n)/2*100
x += 100*n

有什么建议吗?是否有更快的O(1)解决方案?

O(1)解决方案:

const int d = 100;
while (i < limit) { i += x; x += d; }

在Daniel的回答的帮助下,这里是如何在O(1)步骤中计算迭代次数n然后ixi = i+x*n+((n-1)*n)/2*d(见上文)因此我们现在可以解决:

i < limit
= i+x*n+(n*(n+1))/2*d < limit
= d*n^2 + (2*x-d)*n - 2*(limit-i) < 0

上述公式是二次不等式,可以使用quadratic formula

来解决
(-b ± (b^2-4ac)^0.5) / 2a

因此迭代次数n为:

a = d
b = 2*x-d
c = -2*(limit-i)
n = ceil((-b + sqrt(b*b-4*a*c)) / (2*a))

现在我们找到了初始while(for)循环的迭代次数n,我们可以使用这两个公式(见上文)计算ix

i += x*n+((n-1)*n)/2*d
x += d*n

我使用简单的C程序测试了这些公式,它们给出了与while(for)循环相同的结果。

1 个答案:

答案 0 :(得分:2)

这是二次不等式,因此如果可以在O(1)中计算平方根,则可以在O(1)中求解。根据所涉及数字的类型,可能会或可能不会。

如果在开始时i >= limit,那么您很容易没有迭代n = 0。因此,我们假设开头为i < limit,并假设x在每一步中增加一个固定的正数d

那么你要解决的不平等就是

n*(n+1)*d/2 + n*x >= limit - i

通过标准方法求解

n >= sqrt( (1/2 + x/d)^2 + 2*(limit - i)/d ) - (1/2 + x/d)

具有该属性的最小n > 0

ceiling( sqrt( (1/2 + x/d)^2 + 2*(limit - i)/d ) - (1/2 + x/d) )

如果所有数量都能够以double s的足够精度表示,那就是O(1)计算。但是,如果任何数量很大,则浮点计算可能稍微偏离。然后你必须调整。对于中等大小的数量,一步就足够了。

但是如果所有数量都是中等大小,那么二分搜索实际上也是O(1) - 对数是有界的,然后相当小 - 并且可能更快。