【动态规划】斐波那契数列模型总结

一、第 N 个泰波那契数

题目链接: 第 N 个泰波那契数

题目描述:

题目分析:

1、状态表示:

dpi 表示:第 i 个斐波那契数的值

2、状态转移方程:

由题意可知第 i 个数等于其前三个数之和

dpi = dpi-1 + dpi-2 + dpi-3

3、初始化:

由于递推公式中存在 i-1、i-2、i-3,当 i=0、1、2的时候,就会出现-1,-2,-3这种非法的下标值,导致数组访问异常。因此,我们需要在填表前将 0,1,2 位置的值初始化。题目中也直接告诉了我们这些位置的初始值:

dp0=0 、 dp1=1 、 dp2=1

4、优化

其实每次在求取 dpi 的时候,只需要知道其前三个元素的值即可。也就是说我们在每次更新后只需要保存最后的三个数即可。通过三个数的值就能更新出下一个 dp 值。

代码实现:

java 复制代码
class Solution {
    public int tribonacci(int n) {
        int[] dp=new int[]{0,1,1};
        if(n==0)return 0;
        if(n<3)return 1;
        for(int i=3;i<=n;i++){
            dp[i%3]=dp[0]+dp[1]+dp[2];
        }
        return dp[n%3];
    }
}

二、三步问题

题目链接: 三步问题

题目描述:

题目分析:

1、状态表示:
dpi 表⽰:到达 i 位置时,⼀共有多少种⽅法。

2、状态转移方程:

到达第 i 级台阶的所有方法我们不好确定,但我们可以确定到达第 i 级台阶的上一步只有三种可能:

  • 从 i-1置上一级台阶,且到达 i-1 位置的方法数为 dpi-1
  • 从 i-2置上二级台阶,且到达 i-2 位置的方法数为 dpi-2
  • 从 i-3置上三级台阶,且到达 i-3 位置的方法数为 dpi-3

而到达第 i 级台阶的方法数就应该为其所有上一步的方式之和:

因此dpi=dpi-1 + dpi-2 + dpi-3

注意:由于这里计算的结果可能会很大。因此我们需要对结果进行取模。并且为了防止求和时溢出,在每次求和时都要先取模再求和

3、初始化:

由于递推公式中存在 i-1、i-2、i-3,当 i=0、1、2的时候,就会出现-1,-2,-3这种非法的下标值,导致数组访问异常。因此,我们需要在填表前将 0,1,2 位置的值初始化。由题意很容易就能求出这些位置的初始值:

dp0=1 、 dp1=2 、 dp2=4

代码实现:

java 复制代码
class Solution {
    public int waysToStep(int n) {
        if(n==1||n==2)return n;
        if(n==3)return 4;
        int[] dp=new int[n+1];
        dp[1]=1;dp[2]=2;dp[3]=4;
        int MOD=(int)1e9+7;
        for(int i=4;i<=n;i++){
            dp[i]=((dp[i-1]+dp[i-2])%MOD+dp[i-3])%MOD;
        }
        return dp[n];
    }
}

三、 使用最小花费爬楼梯

题目链接:使用最小花费爬楼梯

题目描述:

题目分析:

1、状态表示:
dpi 表⽰:到达 i 位置时的最⼩花费。

2、状态转移方程:
根据最近的⼀步,分情况讨论:

  • 先到达 i - 1 的位置,然后⽀付 costi - 1 ,接下来⾛⼀步⾛到 i 位置:

dpi - 1 + csoti - 1

  • 先到达 i - 2 的位置,然后⽀付 costi - 2 ,接下来⾛⼀步⾛到 i 位置:

dpi - 2 + csoti - 2

我们每次只需要取两种情况的最小值即可。

因此:dpi=Math.min(dpi-1+costi-1,dpi-2+costi-2)

3、初始化:

很明显 i=0 或 i=1时是无法使用递推公式的。因此我们需要先把他们给初始化了。

由题意可得 dp0 = dp1 = 0 ,因为可以直接选择从第0级或第1级台阶开始爬楼梯,不需要任何花费。

代码实现:

java 复制代码
class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int n=cost.length;
        int[] dp=new int[n+1];
        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];
    }
}

四、解码方法

题目链接: 解码方法

题目描述:

题目分析:

1、状态表示:
dpi 表⽰:字符串中 0 , i 区间上,⼀共有多少种编码⽅法。

2、状态转移方程:
关于 i 位置的编码状况,我们可以分为下⾯两种情况:

  • 让 i 位置上的数单独解码成⼀个字⺟;
  • 让 i 位置上的数与 i - 1 位置上的数结合,解码成⼀个字⺟。

下⾯我们就上⾯的两种解码情况,继续分析:
让 i 位置上的数单独解码成⼀个字⺟,就存在两种情况:

  • 解码成功:当 i 位置上的数在 1, 9 之间的时候,说明 i 位置上的数是可以单独解码的,那么此时 0, i 区间上的解码⽅法应该等于 0, i - 1 区间上的解码⽅法。因为 0, i - 1 区间上的所有解码结果,后⾯填上⼀个 i 位置解码后的字⺟就可以了。此时 dpi = dpi - 1
  • 解码失败:当 i 位置上的数是 0 的时候,说明 i 位置上的数是不能单独解码的,那么此时 0, i 区间上不存在解码⽅法。因为 i 位置如果单独参与解码,但是解码失败了,那么前⾯做的努⼒就全部⽩费了。此时 dpi = 0 。

让 i 位置上的数与 i - 1 位置上的数结合在⼀起,解码成⼀个字⺟,也存在两种情况:

  • 解码成功:当结合的数在 10, 26 之间的时候,说明 i - 1, i 两个位置是可以解码成功的,那么此时 0, i 区间上的解码⽅法应该等于 0, i - 2 区间上的解码⽅法,原因同上。此时 dpi = dpi - 2
  • 解码失败:当结合的数在 0, 927 , 99 之间的时候,说明两个位置结合后解码失败(这⾥⼀定要注意 00 01 02 03 04 ...... 这⼏种情况),那么此时 0, i 区间上的解码⽅法就不存在了,原因依旧同上。此时 dpi = 0 。

综上所述: dpi 最终的结果应该是上⾯四种情况下,解码成功的两种的累加和,因此可以得到状态转移⽅程 :

  • 当 si 上的数在 1, 9 区间上时: dpi += dpi - 1
  • 当 si - 1 与 si 上的数结合后,在 10, 26 之间的时候: dpi += dpi - 2
  • 如果上述两个判断都不成⽴,说明没有解码⽅法, dpi 就是默认值 0 。

3、初始化:
可以在最前⾯加上⼀个辅助结点,帮助我们初始化。这时 dpi 就表示 0 , i 区间上的编码数。这里当前两个数能成功解码时,dp2就应该要加上 dp0 的值,因此我们需要让 dp0 初始化为 1。

代码实现:

java 复制代码
class Solution {
    public int numDecodings(String s) {
        char[] cs=s.toCharArray();
        int n=s.length();
        if(cs[0]-'0'==0)return 0;
        int[] dp=new int[n+1];
        dp[1]=1;
        dp[0]=1;
        for(int i=2;i<=n;i++){
            if(cs[i-1]-'0'!=0)
                dp[i]=dp[i-1];
            if(cs[i-2]-'0'==0)continue;
            int x=(cs[i-2]-'0')*10+cs[i-1]-'0';
            if(x<=26){
                dp[i]+=dp[i-2];
            }
        }
        return dp[n];
    }
}

那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步✊

相关推荐
尚早立志几秒前
六)Spring Boot 源码研读之prepareContext 准备上下文
java·spring boot·后端·spring
AI科技星1 小时前
基于全域数学公理体系求解三元约束极值题【乖乖数学】
人工智能·算法·机器学习·密码学·拓扑学·乖乖数学·全域数学
汤姆小白4 小时前
01-环境搭建与项目导览
人工智能·python·机器学习·numpy
Lhappy嘻嘻8 小时前
Java IO|File 文件操作 + 字节流 / 字符流完整笔记 + 递归删除文件实战
java·笔记·php
伊玛目的门徒8 小时前
试用leetcode之典中典 二数之和问题
java·算法·leetcode
Jerry9 小时前
LeetCode 226. 翻转二叉树
算法
想做小南娘,发现自己是女生喵10 小时前
【无标题】
数据结构·算法
向日的葵00610 小时前
langchain的Tools教程(三)
python·langchain·tools
懒鸟一枚11 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
言乐611 小时前
Python实现可运行解密游戏游戏框架
python·游戏·小程序·游戏程序·关卡设计