2017-04-17 137 views
3

我正在學習動態規劃的斐波那契數列的應用程序,並有一個問題。下面是引用代碼:動態規劃斐波那契數列

import java.math.BigInteger; 
import java.util.Arrays; 

public class FibonacciNumbersB { 

    static BigInteger[] dp = new BigInteger[10000]; 

    public static void main(String[] args) { 
     Arrays.fill(dp, BigInteger.ZERO); 
     dp[0] = BigInteger.ONE; 
     dp[1] = BigInteger.ONE; 

     for(int i = 4; i < 9999; i++) 
      System.out.println(fibRecurse(i).toString()); 
    } 

    public static BigInteger fibRecurse(int N) { 
     for(int i = 2; i < N; i++) { 
      // For numerous calls to this function, this will save as it goes 
      if(dp[i].equals(BigInteger.ZERO)) 
       dp[i] = dp[i - 1].add(dp[i - 2]); 
     } 

     return dp[N - 1]; 
    } 
} 

我有一份聲明中檢查,如果dp[i]fibRecurse方法等於0(雖然fibRecurse不是遞歸)。

檢查dp[i]已經計算好還是讓dp[i]等於前兩個元素的總和更有效率?

+0

甚至檢查爲空或重新計算dp [i]是否更有效? @ElliottFrisch –

+0

基準你的代碼。但這不是一個遞歸算法,你的memoization不會幫助。 –

+1

也許我不明白你的問題,但首先檢查值會更有效率,而不是總是重新計算 - 至少對於大型輸入。這不就是動態規劃的全部重點嗎? – 121c

回答

2

我寧願Map<Integer, BigInteger>在執行此記憶化時使用固定BigInteger[]。請注意,您目前的做法是而不是遞歸。該Map可以聲明和像

static Map<Integer, BigInteger> memo = new HashMap<>(); 
static { 
    memo.put(0, BigInteger.ONE); 
    memo.put(1, BigInteger.ONE); 
} 

初始化然後檢查當前n出現在memo(如果是,返回它) - 否則,計算機和存儲。像,

public static BigInteger fibRecurse(int n) { 
    if (memo.containsKey(n)) { 
     return memo.get(n); 
    } 
    BigInteger v = fibRecurse(n - 1).add(fibRecurse(n - 2)); 
    memo.put(n, v); 
    return v; 
} 

一個版本沒有記憶化只會忽略memo

public static BigInteger fibRecurseSlow(int n) { 
    if (n == 0 || n == 1) return BigInteger.ONE; 
    BigInteger v = fibRecurse(n - 1).add(fibRecurse(n - 2)); 
    return v; 
} 

我想你可以推斷我所選擇的方法名是慢

+0

完美,它是有道理的。我一直認爲使用Map 不會是O(1)查找。 –

1
import java.math.BigInteger; 
import java.util.Arrays; 

public class FibonacciNumbersB { 

    static BigInteger[] dp = new BigInteger[10000]; 

    public static void main(String[] args) { 
     dp[0] = BigInteger.ONE; 
     dp[1] = BigInteger.ONE; 
     int N = 9999; 
     fibRecurse(N); 
     for(int i = 0; i < N; i++) 
      System.out.println(dp[i].toString()) ; 
    } 

    public static void fibRecurse(int N) { 
     for(int i = 2; i < N; i++) { 

       dp[i] = dp[i - 1].add(dp[i - 2]); 
     } 
    } 
} 
+0

這是不是比上面的方法慢? –

+0

時間複雜度與@Elliott Frisch的答案相同,即O(n) –

+0

但是對於多次調用,您必須重複計算,而@Elliot Frisch不必這樣做。 –