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);
现在我发现初始for循环的迭代次数n
,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的回答的帮助下,这里是如何在O(1)步骤中计算迭代次数n
然后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
上述公式是二次不等式,可以使用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
,我们可以使用这两个公式(见上文)计算i
和x
:
i += x*n+((n-1)*n)/2*d
x += d*n
我使用简单的C程序测试了这些公式,它们给出了与while(for)循环相同的结果。
答案 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) - 对数是有界的,然后相当小 - 并且可能更快。