【动态规划】——斐波那契数列

动态规划

如何列出正确的状态转移方程:

  1. 确定base case
  2. 确定“状态",也就是原问题和子问题中的变量
  3. 确定选择,也就是导致“状态”产生变化的行为
  4. 明确 dp 函数 / 数组的定义

动态规划的暴力求解阶段就是回溯法。只有有的问题可以通过巧妙的定义,构造出最优子结构,找出重复子问题,可以用DP table或者“备忘录”优化,将递归树大幅剪枝,这就是动态规划的解法。——先找出动态转移方程,再穷举“状态”

回溯法,就是穷举。

斐波那契数列

  1. 暴力递归

    int fib(int N){
    	if(N == 0) return 0;
    	if(N == 1 || N == 2) return 1;
    	return fib(N - 1) + fib(N - 2);
    }
    

    时间复杂度O(2^n)

  2. 带备忘录的递归解法——自顶向下

    每次算出某个子问题的答案后别返回,先将其记到"备忘录"里再返回;每次遇到一个子问题先去备忘录里查

    • 使用数组当“备忘录”
    • 哈希表(字典)
    Integer[] memo;
    public int fib(int n) {
        memo = new Integer[n+1];
        return recursive(n);
    }   
    private int recursive(int num){
        if(memo[num]!=null) return memo[num];
        if(num==0) return 0;
        if(num==1) return 1;
        return memo[num] = ( fib(num-1)+fib(num-2));
    }
    
  3. dp数组的迭代解法——自底向下

    public int fib(int n) {
        if(n == 0) return 0;
        if(n == 1 || n == 2) return 1;
        int[] f= new int[n+1];
        f[0] = 0;
        f[1]= 1;
        for(int i = 2;i<=n;i++) 
            f[i] =f[i-1]+f[i-2];
        return f[n];
    }
    

  4. 优化DP表,两个状态

    int fin(int N){
        if(N == 0) return 0;
        if(N == 2 || N == 1) return 1;
        int prev = 1,curr = 1;
        for(int i = 3;i <= N;i++){
            int sum = prev + curr;
            prev = curr;
            curr = sum;
        }
        return curr;
    }
    
posted @ 2021-03-06 21:26  your_棒棒糖  阅读(120)  评论(0)    收藏  举报