这个for循环的时间复杂度是多少(与`n`有关)?
Posted
技术标签:
【中文标题】这个for循环的时间复杂度是多少(与`n`有关)?【英文标题】:What is the time complexity of this for loop (be related to `n`)? 【发布时间】:2018-11-06 13:07:19 【问题描述】:这个for循环的时间复杂度是多少(与n
有关)?
for(int i = 1, j; i <= n; i = j + 1)
j = n / (n / i);
请注意i
、j
和n
是整数变量,它们遵循整数运算。特别是循环内的表达式n/(n/i)
应该解释如下:
【问题讨论】:
你认为它是什么?您是否尝试过使用不同的n
对其进行测量?
@user463035818 j
在 for 循环的 init decl 中声明。
n / (n / i)
= n * (i / n)
= i
.
@Jabberwocky 是正确的。 j
除了在增量 stmt 中之外不被使用,并且最初在第一次主体迭代时设置。我也双重接受了。
@AlgirdasPreidžius 那些括号是有原因的。当您涉及整数除法时,该表达式不是您认为的那样。
【参考方案1】:
如果我们使用j = i;
而不是j = n / (n / i);
,时间复杂度是O(n)。
现在是j = n / (n / i);
,假设 n = i*k+r,其中 k 和 r 都是整数并且 r = n%i。因此 j = (i*k+r)/((i*k+r)/i) = (i*k+r)/k = i+r/k >= i,这意味着 i 将比使用j = i;
的情况。所以至少时间复杂度小于 O(n),我想这会给你另一个 O(n)。
除了大 O 符号之外,还有另外两个符号(Θ 和 Ω),表示 O(n) 的下限和上限。您可以通过找到这两个界限来获得时间复杂度。还有一个规则,如果我没记错的话,O(k*n) = O(n),系数k不管多大都无所谓。
【讨论】:
@WalterO(n)
表示算法将少于c*n
步骤,因此它与您的O(sqrt(n))
不矛盾(确实更严格)。【参考方案2】:
作为elaborated by taotsi,每次迭代中i
的增量为
inc = 1 + r/k
r=n%i
和 k=n/i
。由于r<i
,增量为1,只要i<sqrt(n)
(因为在整数除法中i*i/n<1
变为0
)。此后,增量(通常)为2
与i<2*sqrt(n)
一样长。这继续类似于几何级数,在sqrt(n)
上给出一个因子 2,即2 sqrt(n)
迭代。
如果我们用整数0 <= b <= 2*a
(即a=int(sqrt(n))
和b=n-a*a
)编写n = a*a+b
,那么简单实验中的总迭代次数总是
b < a? 2*a-1 : 2*a
因此,复杂度为 O(√n)(前提是在循环内完成了一些有用的工作,例如计算总迭代次数,这样编译器就不能省略整个循环)。
【讨论】:
【参考方案3】:由于@Walter 已经提供了证明,我已经为时已晚,但这里是您的代码的 Python3 版本以及作为n
与2*sqrt(n)
函数的函数的迭代次数图.它们看起来大致相同(最多 n = 1e9
)。
import matplotlib.pyplot as plt
from numba import jit
import math
@jit
def weird_increment_loop(n):
i = 1
j = 0
iterations = 0
while i <= n:
j = n // (n // i)
i = j + 1
iterations = iterations + 1
return iterations
iterations = []
func_2sqrt = []
domain = range(0,1000000001,1000000)
for n in domain:
iterations.append(weird_increment_loop(n))
func_2sqrt.append(math.sqrt(n)*2)
plt.plot(domain,iterations)
plt.plot(domain,func_2sqrt)
plt.xlabel("n")
plt.ylabel("iterations(n) and 2*sqrt(n)")
plt.show()
剧情如下:
如果你看不出有什么不同,那是因为几乎没有区别 :D 当然,人们应该永远相信数学 ;)
【讨论】:
【参考方案4】:严格按照 C++ 的规则,它是O(1)
。循环要么在一定数量的没有可观察的工作后终止,要么永远循环(这是未定义的行为)。符合规范的实现可能会假设未遇到未定义的行为,因此我们可以假设它终止。
由于程序的可观察效果不依赖于循环内部发生的事情,因此允许实现将其“假装”成虚无。
【讨论】:
以上是关于这个for循环的时间复杂度是多少(与`n`有关)?的主要内容,如果未能解决你的问题,请参考以下文章