问题是here。我的Python代码是
def solution(A, B):
if len(A) == 1:
return [1]
ways = [0] * (len(A) + 1)
ways[1], ways[2] = 1, 2
for i in xrange(3, len(ways)):
ways[i] = ways[i-1] + ways[i-2]
result = [1] * len(A)
for i in xrange(len(A)):
result[i] = ways[A[i]] & ((1<<B[i]) - 1)
return result
系统检测到的时间复杂度为O(L ^ 2),我不明白为什么。提前谢谢。
答案 0 :(得分:2)
首先,让我们看一下运行时真的是O(L ^ 2)。我复制了你的代码的一部分,并用增加的L:
值来运行它import time
import matplotlib.pyplot as plt
def solution(L):
if L == 0:
return
ways = [0] * (L+5)
ways[1], ways[2] = 1, 2
for i in xrange(3, len(ways)):
ways[i] = ways[i-1] + ways[i-2]
points = []
for L in xrange(0, 100001, 10000):
start = time.time()
solution(L)
points.append(time.time() - start)
plt.plot(points)
plt.show()
要理解为什么这个O(L ^ 2)当明显的时间复杂度&#34;计算表明O(L),注意&#34;时间复杂度&#34;因为它取决于你计算的基本操作,所以它本身并不是一个定义明确的概念。通常,基本操作是理所当然的,但在某些情况下,您需要更加小心。这里,如果将加法计为基本运算,则代码为O(N)。但是,如果计算位(或字节)操作,则代码为O(N ^ 2)。这就是原因:
您正在构建第一个L斐波纳契数的数组。第i个斐波纳契数的长度(以数字表示)是Theta(i)。因此ways[i] = ways[i-1] + ways[i-2]
添加两个大约i
位的数字,如果计算位或字节操作,则需要O(i)时间。
此观察为您提供此循环的O(L ^ 2)位操作计数:
for i in xrange(3, len(ways)):
ways[i] = ways[i-1] + ways[i-2]
对于这个程序,计算位操作是非常合理的:当L增加时,你的数字是无限大的,并且大数字的加法在时钟时间而不是O(1)是线性的。
您可以通过计算斐波纳契数mod 2 ^ 32来修复代码的复杂性 - 因为2 ^ 32是2 ^ B [i]的倍数。这将对你正在处理的数字保持有限的限制:
for i in xrange(3, len(ways)):
ways[i] = (ways[i-1] + ways[i-2]) & ((1<<32) - 1)
代码还有其他一些问题,但这会解决这个问题。
答案 1 :(得分:1)
我已经采用了该功能的相关部分:
def solution(A, B):
for i in xrange(3, len(A) + 1): # replaced ways for clarity
# ...
for i in xrange(len(A)):
# ...
return result
A
是一个可迭代的对象(例如list
)A
的元素A
中元素的数量,使其 O(A) A
上迭代两次,这意味着 2 O(A) - &gt; O(A) 在第4点,由于 2 是一个常数因子, 2 O(A)仍然在 O(A)。
我认为该页面的测量结果不正确。如果循环已嵌套,然后它将是 O(A²),但循环不是嵌套的。
这个简短的样本是 O(N²):
def process_list(my_list):
for i in range(0, len(my_list)):
for j in range(0, len(my_list)):
# do something with my_list[i] and my_list[j]
我没有看到该页面用于“检测”代码的时间复杂度的代码,但我的 guess 是页面正在计算您正在使用的循环数了解代码的大部分实际结构。
<强> EDIT1:强>
请注意,基于this answer,len
函数的时间复杂度实际上是 O(1),而不是 O(N),因此页面没有错误地尝试计算其用于时间复杂度的用途。如果它正在这样做,它将错误地声称更大的增长顺序,因为它分别使用 4 。
<强> EDIT2:强>
正如@PaulHankin指出的那样,渐近分析还取决于什么被认为是“基本操作”。在我的分析中,我使用统一成本法计算了加法和赋值作为“基本操作”,而不是对数成本法,我最初没有提到。
大多数情况下,简单的算术运算始终被视为基本运算。这是我看到最常做的事情,除非被分析的算法本身就是基本操作(例如乘法函数的时间复杂度),这不是这里的情况。
我们有不同结果的唯一原因似乎是这种区别。我认为我们都是正确的。
<强> EDIT3:强>
虽然 O(N)中的算法也在 O(N²)中,但我认为说明代码仍在 O中是合理的( N) b / c,在我们使用的抽象层次上,似乎更相关的计算步骤(即更有影响力)在循环中作为输入可迭代的大小的函数{{1 },而不是用于表示每个值的位数。
考虑以下算法来计算 a n :
A
在统一成本法下,这是在 O(N)中,因为循环执行 n 次,但在对数成本法下,上述算法结果证明因为在{em> O(N)中的行def function(a, n):
r = 1
for i in range(0, n):
r *= a
return r
的乘法的时间复杂度,所以在 O(N²)中,因为位数为表示每个数字取决于数字本身的大小。
答案 2 :(得分:0)
Codility Ladder竞争最好解决in here:
这很棘手。
我们首先为第一个L + 2数字计算斐波那契数列。前两个数字仅用作填充符,因此我们必须将序列索引为A [idx] +1而不是A [idx] -1。第二步是通过删除除n个最低位以外的所有位来替换取模操作