动态规划专题一 斐波那契数问题

目录

 题一 最小花费爬楼梯

1、算法解析

1)确定状态:

​编辑2)状态转移方程:

​编辑3)初始化:

4)填表顺序:

5)返回值:

2、代码

题二 第N个泰波那锲数

1、算法解析

1、确定状态

2、状态转移方程

3、初始化

4、填表顺序

5、返回值

2、代码

3、空间优化版本

 题三 三步问题

1、算法解析

1、确定状态:

2、状态转移方程:

3、初始化:

4、填表顺序:

5、返回值:

2、代码

  题四 解码方法

1、算法解析

1、确定状态:

2、状态转移方程:

3、初始化:

4、填表顺序:

5、返回值:

2、代码


 题一 最小花费爬楼梯

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

1、算法解析

1)确定状态:

确定状态是在干什么?
就是确定状态dp数组中的值代表什么含义。根据分析,我们发现:

状态表的dp[i]值是到达该位置的最小花费


2)状态转移方程:

一般来说,状态转移方程,就是根据i位置之前或者i位置之后,来推导出i的值
只要你能根据之前或或者之后的值来推导出i的值
那么,状态转移方程就出来了
但是,怎么推?
这个就要就题目而言
但是,大体的思路是这样的:根据最近的状态来划分问题

在这个题目中,我们第 i 位置的值,需要前面两个位置的值来确定,其分析过程如下:


3)初始化:

初始化就是保证,在我们进行填表的时候不越界
例如说,我要求dp[0]/dp[1]位置的值,需要前面的位置,但是此时明显已经越界
因此,这两个位置需要单独处理

4)填表顺序:

什么是填表顺序?
很好理解,例如说本题
i位置值得求解,需要前面两个位置的值已经存在才能求解
因此,也就是说在算i位置时,i-1 和 i-2 位置已经填了,已经有值了
所以,在这个题中,我们的填表顺序应该是从前往后,因为后面的值的求解需要前面的值


5)返回值:

因为我们要的是跨过所有台阶,所以这里的返回值是一维数组第n个位置的值
因此,返回值即dp[n]

2、代码

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        //创建dp表(我们要返回n位置,多创建一个位置)
        int n = cost.size();
        vector<int> dp(n+1);

        //初始化(走到0和走到1,是不需要花费的)
        dp[0] = 0;
        dp[1] = 0;
        
        //填表  
        for(int i = 2; i<=n; ++i)
        {
            dp[i] = min((dp[i-1] + cost[i-1]), (dp[i-2] + cost[ i-2 ]));
        }

        //确定返回值
        return dp[n];

    }
};

题二 第N个泰波那锲数

1137. 第 N 个泰波那契数 - 力扣(LeetCode)

1、算法解析


你自己根据我第一题的过程,自己照着求解一般,然后写出代码。

1、确定状态

确定状态是在干什么?
就是确定状态dp数组中的值代表什么含义
dp表里某个位置值的状态就是题目的解

2、状态转移方程

dp[i] = dp[i-1] + dp[i-2] + ap[i-3];题目都直接给了

3、初始化

保证填表的时候越界
根据状态表示方程进行填表
状态方程是dp[i] = dp[i-1] + dp[i-2] + ap[i-3];
因此当i小于3的时候,越界
因此,初始化状态表,dp[0] = 0;dp[1] = ap[2] = 1;

4、填表顺序

从左往右填表,因为第n个位置的值,需要前面三个值已经计算好。

5、返回值

结果是第n个位置的值
所以,返回值就是dp[n](因此需要多创建一个位置的空间)
 

2、代码

class Solution {
public:
    int tribonacci(int n) {

        if(n == 0) return 0;
        if(n == 1|| n == 2) return 1;

        //1、创建dp表
        vector<int> dp(n + 1);

        //2、初始化
        dp[0] = 0;
        dp[1] = dp[2] = 1;

        //3、填表
        for(int i = 3; i<=n; i++ )
            dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
        
        //4、确定返回值
            return dp[n];        


    }
};

3、空间优化版本

//空间优化版本
class Solution {
public:
    int tribonacci(int n) {

        if(n == 0) return 0;
        if(n == 1|| n == 2) return 1;

        int a = 0, b = 1, c = 1, d = 0;
        
        for(int i = 3; i <=n;i++)
        {
            d = a+b+c;
            a = b;
            b = c;
            c = d;
            
        }

        return d;
        
    }
};

 题三 三步问题

面试题 08.01. 三步问题 - 力扣(LeetCode)

1、算法解析

1、确定状态:

定义 dp[i] 数组中的值到底表示什么意思?
很简单,根据题目,就是到达该台阶一共有多少种走法。
我们的目标是求解 dp[n],即上到第 n 阶台阶的方式数量。

2、状态转移方程:

考虑小孩每次可以走 1 阶、2 阶或 3 阶:

因此,状态转移方程为:
dp[i] = dp[i-1] + dp[i-2] + dp[i-3]

3、初始化:

dp[0] = 1:上到第 0 阶只有一种方式,就是不走任何台阶。
dp[1] = 1:上到第 1 阶只有一种方式,就是从地面直接走一阶。
dp[2] = 2:上到第 2 阶有两种方式,可以走两次一阶或者一次两阶。
为什么初始化这三个位置?因为他们需要前面三个位置的值,如果不初始化,会越界。

4、填表顺序:

从 dp[3] 开始一直填充到 dp[n]。

5、返回值:

返回 dp[n],因此要多创建一个位置的空间,同时由于结果可能很大,要对 dp[n] 模 1000000007 取余。

2、代码

class Solution {
public:
    int waysToStep(int n) {
        if(n == 1) return 1;
        if(n == 2) return 2;

        // 1、创建dp表
        vector<int> dp(n + 1);
        
        // 2、初始化
        dp[0] = 1;
        dp[1] = 1;
        dp[2] = 2;

        // 3、填表
        for(int i = 3; i<n+1; ++i)
            dp[i] = ((dp[i-1] + dp[i-2]) % 1000000007 + dp[i-3]) % 1000000007;

        // 4、确定返回值
        return dp[n];
        
    }
};

  题四 解码方法

91. 解码方法 - 力扣(LeetCode)

1、算法解析

1、确定状态:

定义 dp[i] 数组中的值到底表示什么意思:dp[i]的值,就是以i为结尾的编码串的最多解码方式

2、状态转移方程:

因此,状态转移方程为:
dp[i] = dp[i-1] + dp[i-2] 

3、初始化:

为什么初始化这几个位置?因为他们需要前面三个位置的值,如果不初始化,会越界。

4、填表顺序:

从 dp[3] 开始一直填充到 dp[n]。

5、返回值:

返回 dp[n]

2、代码

class Solution {
public:
    int numDecodings(string s) {
    //1、创建dp表
    int n = s.size();
    vector<int> dp(n);

    //只有一位
    dp[0] = s[0] == '0' ? 0 : 1;
    if(n == 1 ) return dp[0];

    //2、初始化
    //根据判断条件进行初始化
    if(s[0] != '0' && s[1] != '0') dp[1]++;
    int m = (s[0] - '0')*10 + (s[1] - '0');//组合编码
    if(m>=10 && m <= 26)
        dp[1] ++;

    //3、填表
    for(int i = 2; i<n; ++i)
    {
        //i位置单独编码
        if( s[i] != '0') dp[i] += dp[i-1];
        //i和i-1位置组合编码
        int x = (s[i-1] - '0')*10 + (s[i] - '0');
        if(x >= 10 && x <= 26) dp[i] += dp[i-2];
    }

    //4、返回值
    return dp[n-1];

    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二十5画生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值