动态规划需要知道的知识点

理论学习笔记:

动态规划问题的一般形式就是求最值。

求解动态规划的核心问题是穷举。因为要求最值,肯定要把所有可行的答案都穷举出来,然后在其中找最值。

动态规划的穷举有点特别,因为这类问题都存在重叠子问题,如果暴力穷举的话效率会极其低下,所以需要 备忘录 或者 DP table 来优化穷举过程,避免不必要的计算。

动态规划问题一定会具备 最优子结构,才能通过子问题的最值得到原问题的最值。

穷举其实并不是容易的事,需要列出正确的 状态转移方程 才能正确的穷举。

由上得到了动态规划的三要素:重叠子问题、最优子结构、状态转移方程。

 

代码随想录:

对于刷题,我们只要知道:动态规划是由前一个状态推导出来的,而贪心是局部直接选最优的。

解题步骤:五部曲,只有五步都搞清楚了,才能说是真正掌握了!

  • 确定dp数组(dp table)以及下标的含义
  • 确定递推公式
  • dp数组如何初始化
  • 确定遍历顺序
  • 举例推导dp数组

 

一、斐波那契数列

class Solution {
public:
    int fib(int N) {
        // 递归解法
        // if (N == 0)
        //     return 0;
        // if (N == 1 || N == 2)
        //     return 1;
        // else
        //     return fib(N-1) + fib(N-2);

        // 动态规划解法,分析步骤见最下方
        if (N <= 1)
            return N;
        vector<int> dp(N+1);
        dp[0] = 0;
        dp[1] = 1;
        for (int i = 2; i <= N; i++) {
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[N];
    }
};
// 时间复杂度:O(n)
// 空间复杂度:O(n)
// 1.确定dp数组以及下标的含义
//     dp[i]的定义为:第i个数的斐波那契数值是dp[i]
// 2.确定递推公式
//     题目已经把递推公式直接给我们了:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2]
// 3.dp数组如何初始化
//     题目中把如何初始化也直接给我们了
//     dp[0] = 0;
//     dp[1] = 1;
// 4.确定遍历顺序
//     从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的
// 5.举例推导dp数组
//     按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:
//     0 1 1 2 3 5 8 13 21 34 55
//     如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的

2、带备忘录的递归解法

class Solution {
public:
    int fib(int N) {
        if(N<1)
            return 0;
        if(N==1 || N==2)
            return 1;
        int prev = 1, curr = 1;//prev记录前一个值,curr记录当前值
        for(int i=3;i<=N;i++)
        {
            int sum = prev + curr;
            prev = curr;
            curr = sum;//当前的值是前两个的和
        }
        return curr;

    }
};

 

posted @ 2021-02-03 19:50  不妨不妨,来日方长  阅读(300)  评论(0编辑  收藏  举报