如何确定包含优化的递归算法的Big O?

时间:2017-10-17 17:55:59

标签: java algorithm recursion big-o

我知道斐波纳契算法的常规递归函数是O(2 ^ n),因为它为每个后续调用调用自己两次,使其成本加倍。但是,在添加了我所看到的描述为优化(序列解决方案的哈希表)后,如何确定它会降低复杂程度(如果有的话)?

例如:

import java.util.*;

public class Solution {

    static Hashtable<Integer, Integer> numbers = new Hashtable<Integer, Integer>();

    public static int fibonacci(int n) {
        if(n == 0 || n == 1){
            return n;
        }else if(numbers.containsKey(n)){
            return numbers.get(n);
        }else {
            int result = fibonacci(n-1) + fibonacci(n-2);
            numbers.put(n, result);
            return result;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        scanner.close();
        System.out.println(fibonacci(n));
    }
}

2 个答案:

答案 0 :(得分:1)

您的算法是O(n)。你实现的是所谓的memoization。这真正意味着当在两个(或一般更多)部分重叠的子问题(例如F(5) = F(4) + F(3))中打破问题时,两者都需要计算F(2)以便它们重叠)当计算一个值时存储,以便下次需要它将被计算。

这意味着,为了计算F(n),您将递归计算所有F(i) ,i<n,如果某些F(i)不止一次需要,它将只计算一次,并且可用于O(1)(由于哈希表)。总体而言是O(n)

这与动态算法版本非常相似(差别很小,而不是建立解决方案,例如F(0),F(1),F(2)... F(n)你做后退保持跟踪你的计算(memoization))。虽然我没有检查你的memoization算法是否有任何bug ...只是解释了memoization算法的概念和复杂性。

答案 1 :(得分:0)

正如评论中所指出的,这个函数的复杂性是Theta(2 ^ n):

Fibonacci(n) {
    if (n < 0) return 0;
    if (n < 2) return 1;
    return Fibonacci(n - 1) + Fibonacci(n - 2);
}

我们可以通过归纳来证明这一点。基本情况:适用于n = 0n = 10.5 * 2^n <= Fibonacci(n) = 1 <= 2 * 2^n。归纳假设:假设这适用于n直到并包括k。归纳步骤:显示0.5 * 2^(k+1) <= Fibonacci(k+1) <= 2 * 2^(k+1)。代替,我们得到0.5 * 2^(k+1) = 2*2^(k-1) <= 2*Fibonacci(k-1) <= Fibonacci(k) + Fibonacci(k-1) <= 2*Fibonacci(k) <= 2 * 2^k <= 2 * 2^(k+1)。这样就完成了证明。

解决方案的散列表(有时称为备忘录,其中 memoization )可防止Fibonacci(k)k次调用一次。由于Fibonacci(n)仅取决于Fibonacci(0)Fibonacci(1),...,Fibonacci(n-1),并且由于哈希表和检查会阻止任何这些被多次调用,因此每个都是只调用一次,并且由于每个都为任何给定的n执行一定量的工作,因此工作总量为O(n)。复发关系现在更难以思考(我们有副作用并且需要条件)所以我必须利用这种“技巧”论证。不幸的是,大多数证据需要某种“技巧”,归纳是一种例外。