Fibonacci的大O有记忆吗?

时间:2016-01-27 00:10:25

标签: python big-o time-complexity memoization

当我运行这个程序时,它似乎是O(1)因为它几乎是非常大的数字而没有记忆。如果它正在计算之前的数字,那么它所要做的只是添加它的结果是O(1)?

memo = {}
def Fib(n):
    if (n < 2):
        return 1
    if not n in memo:
        memo[n] = Fib(n-1) + Fib(n-2)
    return memo[n]

我还将它与没有记忆的斐波纳契程序进行了比较,这里是1到40的情节结果: enter image description here

2 个答案:

答案 0 :(得分:3)

首先,您的算法的下限是O(n),因为对于给定的n,您填充了一个带有n值的字典(假设我们正在处理对{的第一次调用{1}})。

另一方面,Fib函数内的每个n每个操作都会Fib分摊O(1)。总而言之,您可以{{1>} Fib <{> 1}} 第一次致电

请注意,对于较大的O(n),这可能高于n,因为O(n)操作不是not in(仅O(1)已摊销)。 O(1)有多大?不知道,取决于底层的散列函数。另外,在达到n之前,您的内存可能会耗尽。

现在这显然是以空间(即存储器)为代价而变成n。这只是假设每个整数占用相同数量的空间,遗憾的是不适用于Python。 “无限制整数”方法的结果是大整数作为数字数组保存在内存中。由于数字O(n)最多有n个数字(其中log_b(n)+1是数字系统,例如b代表十进制,我不确定哪个Python内部使用)我们得到实际空间复杂度介于10O(n)之间。

如果我们不关心它是否是第一次通话,事情会变得更复杂。但只是一点点。您可以轻松检查O(log_b(n!)) Fib的复杂程度,其中O(max(n-k, 1))是调用时k字典的大小。

将其与例如迭代方法进行比较。在该方法中,您始终保留最后两个元素和一个计数器。这样,您就会获得memo时间复杂度和O(n)空间复杂度。

当然,对于天真的递归Fibonacci,时间复杂度为O(1),空间复杂度为O(2^n)(由于调用堆栈)。

答案 1 :(得分:1)

我的感觉是它仍然是O(n),比如你计算Fin(100),你需要在得到100之前计算所有的数字。当然,如果之前的运行已经完成,那么你将拥有它记忆,但对于你能想象的任何数字并且已经执行过一次,我可以想象一个更大的一个:)

也许你可以说它是O(1)摊销的(与java中的ArrayList的O(1)相同,以获得一个元素......实际上它是O(n),因为你可能需要调整大小数组,但通常情况并非如此,因此O(1)是一个“可接受的”度量。)