刷题day27 动态规划(一)【斐波那契数】【爬楼梯】【使用最小花费爬楼梯】

⚡刷题计划day27 动态规划(一)开始,第三期后是背包专题,可以点个免费的赞哦~

往期可看专栏,关注不迷路,

您的支持是我的最大动力~

目录

什么是动态规划

动态规划的解题步骤

题目一:509. 斐波那契数

题目二:70. 爬楼梯

题目三:746. 使用最小花费爬楼梯


什么是动态规划

动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。

特征:一个问题,可以拆分成一个一个的子问题,解决子问题,顺带解决这个问题

核心思想:拆分子问题,记住过程,减少重复运算。

例子:

  • 1+1+1+1+1+1=? 等于6

  • 在上面式子的在加上一个“1+”。答案是多少?

  • 直接通过之前计算过的答案,再加1

动态规划的解题步骤

做动规题目的时候,很多同学会陷入一个误区,就是以为把状态转移公式背下来,照葫芦画瓢改改,就开始写代码,甚至把题目AC之后,都不太清楚dp[i]表示的是什么。

这就是一种朦胧的状态,然后就把题给过了,遇到稍稍难一点的,可能直接就不会了,然后看题解,然后继续照葫芦画瓢陷入这种恶性循环中

状态转移公式(递推公式)是很重要,但动规不仅仅只有递推公式。

dp五步曲:

  1. 确定dp数组(dp table)以及下标的含义

  2. 确定递推公式

  3. dp数组如何初始化

  4. 确定遍历顺序

  5. 举例推导dp数组

题目一:509. 斐波那契数

509. 斐波那契数

(https://leetcode.cn/problems/fibonacci-number/description/)

斐波那契数大家应该是非常熟悉了,虽然这题简单,但我们目的是用这题加深对解题方法论的理解的

动规五部曲:

1.确定dp数组以及下标的含义

这里我们要用一个一维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数组打印出来看看和我们推导的数列是不是一致的。

法一,代码如下:

class Solution {
    public int fib(int n) {
        if(n<2){
            return n;
        }
        int[] dp =new int[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];
    }
}

法二,其实我们只需维护两个数值就可以了,不用记录整个序列。代码如下:

class Solution {
    public int fib(int n) {
        if(n<2){
            return n;
        }
        int[] dp = new int[2];
        dp[0]=0;
        dp[1]=1;
        for(int i=2;i<=n;i++){
            int sum = dp[0]+dp[1];
            dp[0]=dp[1];
            dp[1]=sum;
        }
        return dp[1];
    }
}

题目二:70. 爬楼梯

70. 爬楼梯

(https://leetcode.cn/problems/climbing-stairs/description/)

这题也十分经典。

爬到第一层楼梯有一种方法,爬到二层楼梯有两种方法。

那么第一层楼梯再跨两步就到第三层 ,第二层楼梯再跨一步就到第三层。

所以到第三层楼梯的状态可以由第二层楼梯 和 到第一层楼梯状态推导出来,那么就可以想到动态规划了。

动规五部曲:

1.确定dp数组以及下标的含义

dp[i]:爬到第i层楼梯,有dp[i]种方法

2.确定递推公式

从dp[i]的定义可以看出,dp[i] 可以有两个方向推出来。

首先是dp[i - 1],上i-1层楼梯,有dp[i - 1]种方法,那么再一步跳一个台阶不就是dp[i]了么。

还有就是dp[i - 2],上i-2层楼梯,有dp[i - 2]种方法,那么再一步跳两个台阶不就是dp[i]了么。

那么dp[i]就是 dp[i - 1]与dp[i - 2]之和!

所以dp[i] = dp[i - 1] + dp[i - 2] 。

在推导dp[i]的时候,一定要时刻想着dp[i]的定义,否则容易跑偏。

3.dp数组如何初始化

再回顾一下dp[i]的定义:爬到第i层楼梯,有dp[i]种方法。

讨论第0层也没什么意义,根据题目可以从1、2层开始:

第1层:dp[1] = 1

第2层:dp[2] = 2

4.确定遍历顺序

从递推公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,遍历顺序一定是从前向后遍历的

5.举例推导dp数组

如果代码出问题了,就把dp table 打印出来,看看究竟是不是和自己推导的一样。

完整代码如下:

class Solution {
    public int climbStairs(int n) {
        if(n<=2){
            return n;
        }
        int[] dp = new int[n+1];
        dp[1]=1;
        dp[2]=2;
        for(int i=3;i<=n;i++){
            dp[i] = dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
}

题目三:746. 使用最小花费爬楼梯

746. 使用最小花费爬楼梯

(https://leetcode.cn/problems/min-cost-climbing-stairs/description/)

注意题目理解,

是可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。然后你当你往上爬时才需要支付费用。

动规五步曲:

1.确定dp数组以及下标的含义

dp[i]:到达第i台阶所支付的最少费用。

2.确定递推公式

可以有两个途径得到dp[i],一个是dp[i-1] 一个是dp[i-2]

dp[i - 1] 跳到 dp[i] 需要花费 dp[i - 1] + cost[i - 1]。

dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]。

那么究竟是选从dp[i - 1]跳还是从dp[i - 2]跳呢?

一定是选最小的,所以dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);

3.dp数组如何初始化

题目“你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。” 也就是说 到达 第 0 个台阶是不花费的,但从 第0 个台阶 往上跳的话,需要花费 cost[0]。

所以初始化 dp[0] = 0,dp[1] = 0;

4.确定遍历顺序

本题的遍历顺序其实比较简单,简单到很多同学都忽略了思考这一步直接就把代码写出来了。

因为是模拟台阶,而且dp[i]由dp[i-1]dp[i-2]推出,所以是从前到后遍历cost数组就可以了。

其实后面稍微有些难度的动态规划,比如背包问题等等,其遍历顺序可能就没那么容易确定下来了,所以还是需要养成考虑遍历顺序的习惯。

5.举例推导dp数组

如果大家代码写出来有问题,就把dp数组打印出来,看看和自己的推导的是不是一样的。

代码如下:

class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int n = cost.length;
        int[] dp = new int[n+1];
        dp[0]=0;// 默认第一步都是不花费体力的
        dp[1]=0;
        for(int i=2;i<=n;i++){
            dp[i] = Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
        }
        return dp[n];
​
    }
}

赞赞~

你可能感兴趣的:(动态规划,算法,数据结构,蓝桥杯,java,面试,背包问题)