for (; i < limit; i += x) {
x += 100;
}
是否有一个优雅的解决方案来计算i
而不x
使用循环结构?
我的想法:
我可以使用流行的高斯求和公式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);
现在我找到了n
初始 for 循环的迭代次数,i
可以x
使用以下方法计算:
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 的回答的帮助下,这里是如何计算迭代次数,n
然后在 O(1) 步骤中计算。(见上文)因此我们现在可以解决:i
x
i = 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
上面的公式是一个二次不等式,可以使用二次公式求解:
(-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))
现在我们找到了n
初始 while (for) 循环的迭代次数,我们可以计算i
并x
使用两个公式(见上文):
i += x*n+((n-1)*n)/2*d
x += d*n
我使用一个简单的 C 程序测试了这些公式,它们给出了与 while (for) 循环相同的结果。