具有记忆功能的斐波那契大 O?

Big-O of Fibonacci with memoization?

当我 运行 这个程序时,它似乎是 O(1) 因为它几乎是用于 fib 的相当大的数字而没有记忆。如果它正在计算之前的数字,那么它所要做的就是相加,结果为 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 的绘图结果:

我的感觉还是O(n),假设你计算Fin(100),你需要计算所有数字才能得到100。当然如果前面的运行已经完成,然后你会把它记在内存中,但是对于你能想象到的任何数字,并且之前执行过 运行,我可以想象一个更大的数字:)

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

首先,你的算法的下限是 O(n),因为对于给定的 n,你用 n 值填充字典(假设我们正在处理第一个调用至 Fib).

另一方面,对于每个 n,您在 Fib 函数中执行的每个操作都被 O(1) 摊销。所以总而言之,你得到 第一次调用 FibO(n) 摊销。

请注意,对于巨大的 n,这可能会超过 O(n),因为 not in 操作不是 O(1)(它只是 O(1) 摊销)。 n 有多大?不知道,取决于底层的哈希函数。另外,在达到 n.

之前,您可能 运行 内存不足

现在这显然是以 space(即内存)为代价的,它也变成了 O(n)。这只是假设每个整数都采用相同数量的 space,不幸的是,Python 并非如此。 "no limit for integers" 方法的结果是大整数作为数字数组保存在内存中。由于数字 n 最多有 log_b(n)+1 位(其中 b 是数字系统,例如 10 表示十进制,我不确定哪个 Python 使用在内部)我们得到真正的 space 复杂度介于 O(n)O(log_b(n!)).

之间

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

例如将其与迭代方法进行比较。在那种方法中,你总是保留 2 个最后的元素和一个计数器。这样你就得到 O(n) 时间复杂度和 O(1) space 复杂度。

当然,对于朴素的递归斐波那契,时间复杂度是 O(2^n)O(n) space 复杂度(由于调用堆栈)。