我正在比较两种确定数字是否为质数的算法。我正在查看时间复杂度的上限,但我无法理解两者之间的时间复杂度差异,尽管实际上一种算法要比另一种算法快。
此伪代码以指数时间O(2 ^ n)运行:
Prime(n):
for i in range(2, n-1)
if n % i == 0
return False
return True
此伪代码的运行时间是上一个示例的一半,但是我一直在努力了解时间复杂度是否仍为O(2 ^ n):
Prime(n):
for i in range(2, (n/2+1))
if n % i == 0
return False
return True
答案 0 :(得分:3)
作为关于big-O(big-O)和big-Θ(big-Theta)的简单直觉,它们是关于在显着增大目标O的大小时如何更改需要执行的操作次数。问题(例如2倍)。
线性时间复杂度意味着您将大小增加了2倍,所需执行的步骤数也增加了约2倍。这就是所谓的Θ(n)
,通常是可互换但不准确的O(n)
(O
和Θ
之间的区别在于O
仅提供上限,而{{ 1}}保证上下限。
对数时间复杂度(Θ
)表示,将大小增加2倍时,需要执行的步骤数将增加一定数量的操作。例如,使用二进制搜索,您只需一次矿石循环迭代就可以在两倍长的列表中找到给定元素。
类似地,指数时间复杂度(对于某些常数Θ(log(N))
,Θ(a^N)
)意味着如果将问题的大小仅增加1,则需要多进行a > 1
倍的运算。 (请注意,a
和Θ(2^N)
之间有细微的差别,实际上第二个更为通用,两者都位于指数时间之内,但两者都不能全部涵盖,请参见wiki一些详细信息)
请注意,这些定义在很大程度上取决于您如何定义“任务的大小”
正如@DavidEisenstat正确指出的那样,可以在两种情况下看到您的算法:
一些固定宽度的数字(例如32位数字)。在这种情况下,素数测试算法复杂性的一个明显度量就是被测值本身。在这种情况下,您的算法是线性的。
实际上,在很多情况下,素数测试算法应适用于非常大的数字。例如,当今使用的许多加密算法(例如Diffie–Hellman key exchange或RSA)都依赖于非常大的素数,例如512位,1024位等等。同样在那些上下文中,安全性是根据那些位数而不是特定的质数来衡量的。因此,在这种情况下,衡量任务大小的自然方法是位数。现在出现了问题:使用您的算法,我们需要执行多少次操作才能检查以位为单位的已知大小的值?显然,如果值2^Θ(N)
具有N
位,则它约为m
。因此,您的算法从线性N ≈ 2^m
转换为指数Θ(N)
。换句话说,要解决一个仅长1位的值的问题,就需要做大约2倍的工作。
答案 1 :(得分:1)
指数与线性是一个有关如何表示输入和机器模型的问题。如果输入以一元表示(例如,将7发送为1111111),并且机器可以对数字进行恒定的时分,那么可以,该算法是线性时间。但是,n的二进制表示形式大约使用lg n位,并且数量n与lg n呈指数关系(n = 2 ^(lg n))。
鉴于两种解决方案的循环迭代次数均在一个常数因子之内,所以它们在同一大O类Theta(n)中。如果输入具有lg n位,则为指数;如果输入具有n位,则为线性。
答案 2 :(得分:0)
我希望这能为您解释为什么它们实际上是线性的。
假设您调用函数并查看它们执行了多少时间
Prime(n): # 1 time
for i in range(2, n-1) #n-1-1 times
if n % i == 0 # 1 time
return False # 1 time
return True # 1 time
# overall -> n
Prime(n): # Time
for i in range(2, (n/2+1)) # n//(2+1) -1-1 time
if n % i == 0 # 1 time
return False # 1 time
return True # 1 time
# overall -> n/2 times -> n times
这表明素数是线性函数
O(n ^ 2)可能是由于调用此函数的代码块引起的。