动态规划--斐波那契数列模型

算法原理

动态规划解决的一般步骤

1.状态表示

2.状态转移方程

3.初始化

4.填表顺序

5.返回值

本文通过4道例题总结利用动态规划的思想来解决斐波那契数列模型

题目

1. 第 N 个泰波那契数

1.题目描述

泰波那契序列定义如下:

T0 =0,T1=1,且在n>=0的条件下,Tn+3 = Tn+Tn+1+Tn+2

给你整数n,请你返回第n个泰波那契序列Tn的值

2.算法原理

这里我们按照解决动态规划的五步逐一分析

1.状态表示

什么是状态表示? dp表里面的值所表示的含义

如何得到状态表示?1.题目要求 2.经验+题目要求 3.分析问题的过程中,发现重复子问题

2.状态转移方程

dpi 等于什么?

这里题目已经告诉我们了 dpi = dpi-3 +dpi-2 +dpi-1

3.初始化

int\[\] dp = new intn+1

初始化的目的是为了保证填表的时候不越界

这道题目已经告诉我们T0 = 0 T1=1 T2=1

4.填表顺序 从左到右

为了填写当前状态的时候,所需要的状态已经计算过了

5.返回值

根据题目要求 返回dpn

3.代码实现

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

4.空间优化

动态规划一般使用滚动数组进行优化

需要的是连续的几个

java 复制代码
class Solution {
    public int tribonacci(int n) {
        if(n==0||n==1){
            return  n;
        }
        if(n==2){
            return 1;
        }
       int p = 0;
       int q = 0;
       int r = 1;
       int s = 1;
       for(int i = 3;i<=n;i++){
        p = q;
        q = r;
        r = s;
        s = p +q + r;
       }
       return s;
    }
}

2.三步问题

1.题目描述

三步问题,有个小孩正在上楼梯 楼梯有n阶台阶,小孩一次可以上1阶,2阶或3阶 实现一种方法,计算小孩有多少种上楼方式,结果可能很大,你需要对结果模1000000007

2.算法原理

1.状态表示

根据经验(以某个位置为结尾或以某个位置为起点)+题目要求

dpi表示以i位置为结尾时,到达i位置时一共有多少种方法

2.状态转移方程

以i位置状态,最近的一步,来划分问题

i-1跳1步可以到达 i-2跳2步 i-3跳3步可以到达

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

3.初始化

dp1 = 1 dp2 = 2 dp3 = 4

4.填表顺序

从左往右

5.返回值

dpn;

3.代码实现

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

3.使用最小花费爬楼梯

1.题目描述

给你一个整数数组cost,其中costi是从楼梯第i个台阶向上爬需要支付的费用,一旦你支付此费用,即可选择向上爬一个或者两个台阶

你可以选择从下标为0或下标为i的台阶开始爬楼梯

请你计算并返回楼梯顶部的最低花费

我们结合实例1 cost=10,15,20 输出为14 从下标为1的台阶开始,支付15向上爬两个台阶,到达楼梯顶部,总花费15

可以知道楼顶是在数组的下一个位置

2.算法原理

解法一:以i位置为结尾

1.状态表示

经验+题目要求

以i位置为结尾,dpi表示到达i位置的最小花费

2.状态转移方程

用之前或者之后的状态,推导出dpi的值

根据最近的一步划分问题

dpi = min(dpi-1+costi-1+dpi-2+cost[i-2)

先到达i-1位置,支付costi-1 走一步花费 dpi-1+costi-1

先到达i-2位置,支付costi-2 走两步花费dpi-2+costi-2

3.初始化

dp = new intn+1

dp0 = 0;

dp1 = 0;

4.填表顺序

从左到右

保证填表的时候是不越界的

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.状态表示 以i位置为起点

dpi表示:从i位置出发,到达楼顶,这是的最小花费

2.状态转移方程

dpi 支付costi 走一步 从i+1位置出发,到终点 dpi+1+costi

支付costi 走两步 从i+2位置出发到终点 dpi+2+costi

两者取最小值

3.初始化

和原始数组同等规模

dpn-1 = costn-1

dpn-2 = costn-2

4.填表顺序

从右向左

5.返回值

返回dp0 dp1 的最小值

java 复制代码
class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int n = cost.length;
        int[] dp = new int[n];
        dp[n-1] = cost[n-1];
        dp[n-2] = cost[n-2];
        for(int i = n-3;i>=0;i--){
            dp[i] = Math.min(dp[i+1],dp[i+2])+cost[i];
        }
        return Math.min(dp[0],dp[1]);
    }
}

4.解码方法

1.题目描述

一条包含字母A-Z的消息通过一下映射进行了编码:

'1'->'A' ... '26'->'Z'

然而,在解码已编码的消息时.你意识到有许多不同的方式来解码,因为有些编码被包含在其他编码中('2' 和'5' 与'25')

给定一个只含数字的非空字符串s,请计算并返回解码方法的总数,如果没有合法的方式解码整个字符串,返回0

(不能有前导0)

2.算法原理

1.状态表示

经验+题目要求

以某个位置为起点/结尾

dpi 表示:以i位置为结尾的时候,解码方法的总数

2.状态转移方程

根据最近的一步划分问题

dpi si单独解码 成功 1<=a<= 9 ->dpi-1 失败 0

si-1与si 解码 成功 10<=b*10+a<=26 dpi-2 失败 0

dpi = dpi-1 + dpi-2 (只有成功才能加)

3.初始化

dp0 = 1 (如果第一个字符是1<=a<=9) 不然就是0

dp1 = 0/1/2

处理边界问题以及初始化问题的技巧

加一个虚拟节点 注意:1.虚拟节点的值要保证后面的填表是正确的

2.下标的映射关系

dp0不能是0

这里是1

dp2 = dp1+dp0

4.填表顺序

从左向右

5.返回值

dpn

3.代码实现

java 复制代码
class Solution {
    public int numDecodings(String ss) {
        int n = ss.length();
        char[] s = ss.toCharArray();
        int[] dp = new int[n+1];
        dp[0] = 1;
        if(s[0]!='0'){
            dp[0] = 1;
            dp[1] = 1;
        }
        for(int i = 2;i<=n;i++){
            if(s[i-1]!='0'){
                dp[i] += dp[i-1];
            }
            int tp = (s[i-2]-'0')*10 +s[i-1]-'0';
            if(tp>=10&&tp<=26){
                dp[i]+=dp[i-2];
            }
        }
        return dp[n];
    
    }
}
相关推荐
IT猿手1 小时前
多目标优化算法:多目标蛇优化算法(Multiple Objective Snake Optimizer,MOSO)(提供MATLAB代码)
开发语言·算法·matlab·动态路径规划·光伏模型参数估计
MegaDataFlowers1 小时前
101.对称二叉树
算法
Jasmine_llq2 小时前
《B3939 [GESP样题 四级] 绝对素数》
数据结构·算法·素数判断算法·数字拆分与反转算法·区间遍历枚举·双条件判断逻辑
workflower2 小时前
具身智能研究对象:物理交互中的智能行为
设计模式·动态规划·软件工程·软件构建·scrum
郝学胜-神的一滴2 小时前
干货版《算法导论》07:递归视角下的选择排序与归并排序
java·数据结构·c++·python·程序人生·算法·排序算法
csdn_aspnet2 小时前
javascript 算法 LeetCode 编号 70 - 爬楼梯
开发语言·javascript·算法·leetcode·ecmascript
shehuiyuelaiyuehao2 小时前
多线程入门
java·python·算法
Navigator_Z2 小时前
LeetCode //C - 1073. Adding Two Negabinary Numbers
c语言·算法·leetcode
醇氧2 小时前
【OpenClaw】更换阿里百炼完整配置指南
算法·ai