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的答案的帮助下,这里是如何计算迭代次数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
上面的公式是二次不等式,可以使用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)循环相同的结果.
最佳答案 这是一个二次不等式,所以你可以在O(1)中解决它,如果你可以在O(1)中计算平方根.取决于所涉及的数字的类型,可能是也可能是不可能的.
如果i> =开始时的限制,那么你通常没有迭代,n = 0.所以让我们假设i
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) )
如果所有数量都能够以足够的精度表示为双精度,那么就是O(1)计算.但是,如果任何数量很大,则浮点计算可能稍微偏离.然后你必须调整.对于中等大小的数量,一步就足够了.
但是如果所有数量都是中等大小的,那么二分搜索实际上也是O(1) – 对数是有界的,然后相当小 – 并且可能更快.