代码随想录算法训练营 动态规划part01

一、理论基础 

对于动态规划问题,可拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!

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

为什么要先确定递推公式,然后在考虑初始化呢?

因为一些情况是递推公式决定了dp数组要如何初始化!

二、斐波那契数 

509. 斐波那契数 - 力扣(LeetCode)

解题思路
斐波那契数列的定义是 f(n+1)=f(n)+f(n−1) ,生成第 n 项的做法有以下几种:

暴力搜索
原理: 把 f(n) 问题的计算拆分成 f(n−1) 和 f(n−2) 两个子问题的计算,并递归,以 f(0) 和 f(1) 为终止条件。
缺点: 大量重复的递归计算,例如 f(n) 和 f(n−1) 两者向下递归需要 各自计算 f(n−2) 的值。
记忆化递归
原理: 在递归法的基础上,新建一个长度为 nnn 的数组,用于在递归时存储 f(0) 至 f(n) 的数字值,重复遇到某数字则直接从数组取用,避免了重复的递归计算。
缺点: 记忆化存储需要使用 O(N)的额外空间。
动态规划
原理: 以斐波那契数列性质 f(n+1)=f(n)+f(n−1) 为转移方程。
从计算效率、空间复杂度上看,动态规划是本题的最佳解法。

动态规划解析:
状态定义: 设 dp 为一维数组,其中 dp[i]的值代表 斐波那契数列第 i 个数字 。
转移方程: dp[i+1]=dp[i]+dp[i−1] ,即对应数列定义 f(n+1)=f(n)+f(n−1)。
初始状态: dp[0]=0, dp[1]=1 ,即初始化前两个数字。
返回值: dp[n] ,即斐波那契数列的第 n 个数字。

由于 dp 列表第 iii 项只与第 i−1 和第 i−2 项有关,因此只需要初始化三个整形变量 sum, a, b ,利用辅助变量 sum 使 a,b 两数字交替前进即可 (具体实现见代码) 。
节省了 dp 列表空间,因此空间复杂度降至 O(1) 。

class Solution {
    public int fib(int n) {
        int a = 0, b = 1, sum;
        for(int i = 0; i < n; i++){
            sum = a + b;
            a = b;
            b = sum;
        }
        return a;
    }
}

三、 爬楼梯 

70. 爬楼梯 - 力扣(LeetCode)

大神题解70. 爬楼梯 - 力扣(LeetCode)

class Solution {
    public int climbStairs(int n) {
        double sqrt_5 = Math.sqrt(5);
        double fib_n = Math.pow((1 + sqrt_5) / 2, n + 1) - Math.pow((1 - sqrt_5) / 2,n + 1);
        return (int)(fib_n / sqrt_5);
    }
}

四、使用最小花费爬楼梯 

746. 使用最小花费爬楼梯 - 力扣(LeetCode)

┭┮﹏┭┮746. 使用最小花费爬楼梯 - 力扣(LeetCode)

你可能感兴趣的:(动态规划,算法)