Java【动态规划】斐波那契数列模型, 图文详解 + 代码

news2024/11/15 8:32:40

文章目录

  • 一、第 N 个泰波那契数
    • 1, 题目
    • 2, 思路分析
      • 2.1, 状态表示
      • 2.2, 状态转移方程
      • 2.3, 初始化
      • 2.4, 填表顺序
      • 2.5, 返回值
    • 3, 代码
  • 二、三步问题
    • 1, 题目
    • 2, 思路分析
      • 2.1, 状态表示
      • 2.2, 状态转移方程
      • 2.3, 初始化
      • 2.4, 填表顺序
      • 2.5, 返回值
    • 3, 代码
  • 三、
    • 1, 题目
    • 2, 思路分析
      • 2.1, 状态表示
      • 2.2, 状态转移方程
      • 2.3, 初始化
      • 2.4, 填表顺序
      • 2.5, 返回值
    • 3, 代码
  • 四、
    • 1, 题目
    • 2, 思路分析
      • 2.1, 状态表示
      • 2.2, 状态转移方程
      • 2.3, 初始化
      • 2.4, 填表顺序
      • 2.5, 返回值
    • 3, 代码

本篇总结动态规划中的斐波那契数列模型的解法和思路

按照以下流程进行分析题目和代码编写

思路分析步骤代码编写步骤
1, 状态表示1, 构造 dp 表
2, 状态转移方程2, 初始化+边界处理
3, 初始化3, 填表(抄状态转移方程)
4, 填表顺序4, 返回结果
5, 返回值/

一、第 N 个泰波那契数

1, 题目

OJ链接

题目分析: 第 N 个数 = 第 N-1 个数 + 第 N-2 个数 + 第 N-3 个数


2, 思路分析

2.1, 状态表示

根据题目要求, 要我们算出第 N 个数是多少, 我们要构造一个dp表(数组), 表中的值就是第 N 个数的值

所以对于整个数列来说, 对于 i(任意数) 位置, 都可以表示成 dp[i]

状态表示 : dp[i] 就是第 i 个泰波那契数


2.2, 状态转移方程

根据 : 第 N 个数 = 第 N-1 个数 + 第 N-2 个数 + 第 N-3 个数 可直接得出

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

在这里插入图片描述


2.3, 初始化

初始化是为了填表的时候不越界访问

根据状态转移方程可以分析出, dp[i] 依赖前三个数的值, 所以在表中前三个数的值必须手动填, 从第四个数开始可以根据状态转移方程来填

题中已经告诉我们 dp[0] = 0, dp[1] = dp[2] = 1


2.4, 填表顺序

由于dp[i] 依赖前三个数的值, 所以在确定任意位置的值时, 首先要知道前三个数的值, 所以填表顺序是从左往右


2.5, 返回值

要我们求第 N 个数的值, 就是 dp[N]

要访问 dp[N] , dp 表的长度是多少?


3, 代码

在构造 dp 表时, int[] dp = new int[n];是错的, 长度为 n 的数组, 下标是 0 ~ n-1, 要想访问到 dp[n], dp 表的长度应该是 n + 1

public int tribonacci(int n) {
        // 1, 构造dp表
        int[] dp = new int[n + 1];
        // 2, 初始化 + 边界条件判断
        if(n == 0 || n == 1) {
            return n;
        }
        if(n == 2) {
            return 1;
        }
        dp[0] = 0;
        dp[1] = 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];
    }

二、三步问题

1, 题目

OJ链接

分析题目得知, 在第 N 个台阶时, 可以从第 N - 1 个台阶跳一个台阶上来, 可以从第 N - 2 个台阶跳两个台阶上来, 可以从第 N - 3 个台阶跳三个台阶上来


2, 思路分析

2.1, 状态表示

根据题目要求可知, 在 dp 表中的值就是到达某个台阶时的跳法总数

状态表示 : dp[i] 就是到达第 i 个台阶时, 跳法的总数


2.2, 状态转移方程

以 i 位置状态的最近的⼀步,来分情况讨论, 要求 dp[i], 已经分析过有三种情况

  • 在第 i - 1 个台阶时, 有 ? 种跳法, 加一步即可
  • 从第 i - 2 个台阶时, 有 ? 种跳法, 加一步即可
  • 从第 i - 3 个台阶时, 有 ? 种跳法, 加一步即可

所以在第 i 个台阶时的跳法总数就是 : 上述三个状态的跳法总数的和

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

问 : 为什么不是 dp[i] = dp[i - 1] + 1 + dp[i - 2] + 1 + dp[i - 3] + 1 呢? 不是多跳了一步吗?
答 : 是多跳了一步, 但只是在原有的跳法上多跳了一下, 并没有产生新的跳法!!! 这一点一定要理解, 我们求的是有多少种跳法, 而不是跳了多少步!!

实在不理解可以带入第二个台阶, 进行分析
在这里插入图片描述


2.3, 初始化

初始化是为了填表的时候不越界访问

根据状态转移方程可以分析出, dp[i] 依赖前三个数的值, 所以在表中前三个数的值必须手动填, 从第四个数开始可以根据状态转移方程来填

可以简单推导出 dp[1] = 1, dp[2] = 2, dp[3] = 4;

我们让 0 号台阶表示地平线, 不需要给 dp[0] 赋值, 没有意义


2.4, 填表顺序

由于dp[i] 依赖前三个数的值, 所以在确定任意位置的值时, 首先要知道前三个数的值, 所以填表顺序是从左往右


2.5, 返回值

要我们求第 N 个数的值, 就是 dp[N]

要访问 dp[N] , 初始化时 dp 表的长度是多少?


3, 代码

在构造 dp 表时, int[] dp = new int[n];是错的, 长度为 n 的数组, 下标是 0 ~ n-1, 要想访问到 dp[n], dp 表的长度应该是 n + 1

	public int waysToStep(int n) {
        // 1, 构造dp表
        int[] dp = new int[n + 1];
        // 2, 初始化+边界条件处理
        if(n <= 2) {
            return n;
        }
        dp[1] = 1;
        dp[2] = 2;
        dp[3] = 4;
        // 3, 填表(抄状态转移方程)
        for(int i = 4; i <= n ; i++) {
            dp[i] = ((dp[i - 1]  + dp[i - 2]) % 1000000007 +  dp[i-3]) % 1000000007;
        }
        // 4, 返回值
        return dp[n];
    }

三、

1, 题目

OJ链接

分析题目得知, 要达第 N 个台阶, 可以从第 N-1个台阶过来, 也可以从第 N-2 个台阶过来, 如果 cost 数组的长度为 n , 台阶数为 n - 1, 因为 cost[0] 表示从地平线起跳要支付的费用, 楼顶在 n 的位置


2, 思路分析

2.1, 状态表示

我们需要构造 dp 表, 要求到达楼顶的最小花费, 需要先知道中途到达任意位置的最小花费(划分子问题), 所以 状态表示 : dp[i] 就是以 i 为终点, 到达 i 位置的最小花费


2.2, 状态转移方程

以 i 位置状态的最近的⼀步,来分情况讨论, 要求 dp[i](到达 i 位置的最小花费), 有两种情况

  • 从第 i - 1 位置上来 : 在此位置的最小花费 + 从此位置起跳要支付的费用
  • 从第 i - 2 位置上来 : 在此位置的最小花费 + 从此位置起跳要支付的费用

要保证到达 i 位置时花费的钱最少, 就要对这两种方式的费用取较小值

注意题中给的 cost 数组和 dp 数组的关系 :
在这里插入图片描述

状态转移方程 : dp[i] = min (dp[i - 1] + cost[i- 1], dp[i - 2] + cost[i- 2])


2.3, 初始化

初始化是为了填表的时候不越界访问

根据状态转移方程可知, 填 dp 表中的值, 依赖前两个位置的值, 所以在 dp 表中, 0 下标和 1 下标必须初始化

题目已经说明, 可以自由选择从 0 号台阶或 1 号台阶起跳, 所以到达 0 号台阶或 1 号台阶的最小花费为 0 元, 所以 : dp[0] = 0, dp[1] = 0;


2.4, 填表顺序

dp[i] 的值依赖前两个位置的值, 所以填表顺序是从左往右


2.5, 返回值

cost 长度为 N, 则有 N - 1 个台阶, 楼顶在 N 位置, 所以返回 dp[N]

要访问 dp[N] , 初始化时 dp 表的长度是多少?


3, 代码

在构造 dp 表时, int[] dp = new int[n];是错的, 长度为 n 的数组, 下标是 0 ~ n-1, 要想访问到 dp[n], dp 表的长度应该是 n + 1

	public int minCostClimbingStairs(int[] cost) {
        // 构造dp表
        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];
    }

四、

1, 题目

OJ链接


2, 思路分析

2.1, 状态表示

在这里插入图片描述

状态表示 : dp[i] 就是以 i 位置为结尾, 编码方法的总数


2.2, 状态转移方程

以 i 位置状态的最近的⼀步,来分情况讨论, 要求 dp[i], 有两种方式 :

  • i 位置的数字单独解码, 如果解码成功, dp[i] 加上 x , (从0 到 i - 1位置的所有解码方法总数)在这里插入图片描述

  • i 位置的数字和 i - 1 位置的数字一起解码, 如果解码成功, dp[i] 加上 y , (从0 到 i - 2位置的所有解码方法总数)
    在这里插入图片描述

结合状态表示可知 : x = 从0 到 i - 1位置的所有解码方法总数 = dp[i- 1], y = 从0 到 i - 1位置的所有解码方法总数 = dp[i- 2]

所以状态转移方程 : 如果方案一成功, dp[i] += dp[i-1], 如果方案二成功, dp[i] += dp[i-2],

这里千万要搞清楚, 无论哪种方式解码, 都在只是增加了解码的字符串长度, 而不是新增了一种解码方式

无论哪种方式解码, 一旦解码失败, dp[i] += 0 即可, 如果当前位置的解码方式为 0, 计算到下一个位置时, 会依赖当前位置的 dp 值, 所以后面 dp 表中的值都为 0, 最终返回结果为 0


2.3, 初始化

初始化是为了填表的时候不越界访问

根据状态转移方程可知, 填表到某一位置时, 依赖前两个位置的值, 所以初始化dp表中 0 下标和 1 下标即可


2.4, 填表顺序

填表顺序是从左往右


2.5, 返回值

要求的是整个字符串的解码方案总数, 令字符串长度为 n, 返回dp[n - 1]


3, 代码

    public int numDecodings(String s) {
        // 构造 dp 表
        int n = s.length();
        int[] dp = new int[n];
        char[] array = s.toCharArray();
        // 初始化+边界条件
        if(array[0] != '0') {
            dp[0] = 1;
        }
        if(n == 1) {
            return dp[0];
        }
        if( array[1] != '0') {
            dp[1] += dp[0];
        }
        int num = (array[0] -'0') * 10 + (array[1]-'0');
        if( num >= 10 && num <= 26 ) {
            dp[1] += dp[0];
        }
        // 填表(抄状态转移方程)
        for(int i = 2; i < n; i++) {
            if(array[i] != '0') {
                dp[i] += dp[i - 1];
            }
            num = (array[i-1] -'0') * 10 + (array[i]-'0');
            if( num >= 10 && num <= 26 ) {
                dp[i] += dp[i - 2];
            }
        }
        // 返回值
        return dp[n - 1];
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/710545.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis 高可用和优化

目录 一&#xff1a;Redis 高可用 二&#xff1a; Redis 持久化 1、持久化的功能 2、Redis 提供两种方式进行持久化 3、 RDB 持久化 &#xff08;1&#xff09;触发条件 &#xff08;1.1&#xff09;手动触发 &#xff08;1.2&#xff09;自动触发 &#xff08;1.3&am…

软件测试岗位之大厂到底有多累?

今天给大家分享两个朋友的故事&#xff0c;他们分别在国内两家顶尖的互联网大厂&#xff0c;一个在头条&#xff0c;一个在蚂蚁。 头条的故事 头条的主人公&#xff0c;在入职后的一年里&#xff0c;晚上十点半下班是比较早了&#xff0c;基本上都是十一点半左右下班&#xff…

Redmi4X刷入Ubuntu touch真正成为一台远程无需人操作的云服务器(就是配置垃圾)

前言 前几天把高一买的手机相册和文件拷贝到了电脑上&#xff0c;寻思这旧手机还能干嘛&#xff0c;搜了一下有做监控的&#xff0c;行车记录仪的&#xff0c;最后决定还是做Linux服务器香啊。用了一天时间参考网上的教程做完了&#xff0c;自己再做一下总结和一些弯路记录。 …

ctemplate

参考安装 原理&#xff1a; 如何使用&#xff1f; // test_ctemplate.cc #include <iostream> #include <string> #include <ctemplate/template.h>int main() {std::string in_html "./test.html";std::string value "一行白鹭上青天&q…

一、设计模式的作用和六大原则

文章目录 引言1.设计模式1.1 设计模式的目的1.2 设计模式六大原则1.2.1 单一职责原则&#xff08;类、方法和接口&#xff0c;保持职责单一性&#xff0c;如:Activity和Adapter分成两个类&#xff09;1.2.2. 开闭原则&#xff08;扩展开放&#xff0c;修改关闭&#xff1b;如&a…

python 数字进制

python 数字进制 1、数学中进制对应代码2、Python进制转换函数 1、数学中进制对应代码 十六进制&#xff1a; 0x11 八进制&#xff1a; 0o11 二进制&#xff1a; 0b11 十进制&#xff1a; 11&#xff08;啥都不加默认为十进制&#xff09; #!/usr/bin/python # -*- coding: UTF…

第133页的gtk+编程例子——编写计算器应用

第133页的gtk编程例子——编写计算器应用 以下gtk编程例子是来自书籍《实用技术&#xff1a;开发Linux应用——用GTK和GDK开发Linux图形用户界面应用》第133页的内容——编写计算器应用 例子程序是在gtk2.0编译的&#xff0c;已经修改许多地方才能在gtk3.0编译通过&#xff0c…

数学建模——插值(上)

本文是面向数学建模准备的&#xff0c;是介绍性文章&#xff0c;没有过多关于原理的说明&#xff01;&#xff01;&#xff01; 插值方法简介 插值问题 已知区间[a,b]上有系列观测值(xi,yi),i0,1,2,…,n&#xff0c;求一条曲线把这些点依次连接起来&#xff0c;称为插值&#…

在idea中高并发下的分布式锁以及解决方法

案例:1.互联网秒杀 2.抢优惠卷 3.接口幂 引入pom文件 <packaging>war</packaging><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.8.RELEA…

分布式软件架构——客户端缓存

浏览器的客户端缓存 当万维网刚刚出现的时候&#xff0c;浏览器的缓存机制差不多就已经存在了。在 HTTP 协议设计之初&#xff0c;人们便确定了服务端与客户端之间“无状态”&#xff08;Stateless&#xff09;的交互原则&#xff0c;即要求客户端的每次请求是独立的&#xff…

MySQL环境搭建(Windows电脑)

MySQL环境搭建-Windows电脑篇 软件获取&#xff1a; 搜索gzh【李桥桉】&#xff0c;需要win电脑安装包&#xff0c;回复【win-MS】。 搜索gzh【李桥桉】&#xff0c;需要mac电脑安装包&#xff0c;回复【mac-MS】。 注意&#xff1a;确保电脑为64位系统&#xff08;不是的话需要…

华为手环8相册表盘使用指南

随着科技的发展&#xff0c;智能手环已经成为越来越多人的选择。华为手环8作为一款备受好评的智能手环&#xff0c;不仅具备精准的监测功能&#xff0c;还拥有丰富的表盘样式。本文将向您介绍华为手环8如何使用相册表盘&#xff0c;通过这一功能&#xff0c;您可以轻松地将您的…

Windows 打开cmd/dos窗口的12种方式(全网最全)

文章目录 1. 从开始菜单的应用列表打开2. 从搜索打开3. 从运行打开4. 从文件资源管理器打开5. 从C:\Windows\System32\cmd.exe打开6. 从桌面>快捷方式打开&#xff08;需自己创建&#xff09;7. 从任务栏>快捷方式打开&#xff08;需自己创建&#xff09;8. 从开始菜单&g…

TV快应用系列——1.ExtScreen框架快速入门

系列文章目录 TV快应用系列——1.ExtScreen框架快速入门 ExtScreen框架快速入门 系列文章目录前言一、ExtScreen简介整体结构扩展屏和应用的区别 二、安装和环境配置1.安装编辑工具2.安装Vue开发环境1.1.1安装 Node1.1.2安装配置 npm下载安装npmnpm 设置淘宝镜像安装 vue-cli&…

图像分割的大变革:从SAM(分割一切)到FastSAM、MobileSAM

前言 SAM就是一类处理图像分割任务的通用模型。与以往只能处理某种特定类型图片的图像分割模型不同&#xff0c;SAM可以处理所有类型的图像。 在SAM出现前&#xff0c;基本上所有的图像分割模型都是专有模型。比如&#xff0c;在医学领域&#xff0c;有专门分割核磁图像的人工…

『DotNetBrowser』在.Net中的浏览器嵌入组件,该选择DotNetBrowser 还是 CefSharp?

&#x1f4e3;读完这篇文章里你能收获到 全方位对比DotNetBrowser 和 CefSharp的优缺点 文章目录 一、引言二、引擎三、架构1. CefSharp架构2. DotNetBrowser架构 四、对比1. 稳定性和内存使用2. 应用程序域3. AnyCPU4. H.264, AAC5. 安全6. Visual Studio设计器7. 嵌入应用程…

八、c++学习(加餐4:深入分析new和delete)

经过了两篇的类和对象分析&#xff0c;我们这一篇再次加餐&#xff0c;对new和malloc的分析&#xff0c;malloc的源码不在这篇介绍&#xff0c;会放到linux篇的内存池专题&#xff0c;所以我们这篇只要分析new。 这篇的主要目的就是&#xff0c;对象是怎么new出来的&#xff0…

技术干货——Selenium Python使用技巧(三)

目录 处理不同情况的等待 网页中的滚动操作 使用Selenium放大和缩小 查找元素的大小 获取元素的X和Y坐标 使用自定义配置文件禁用JavaScript 设置手动代理设置 总结&#xff1a; 处理不同情况的等待 在Selenium自动化测试中网页可能需要花费一些时间来加载&#xff0c;…

MybatisPlus从入门到精通-基础篇

文章目录 一、概述二、快速入门2.1 数据库准备2.2 创建springboot工程2.3 实体类准备2.4 测试MybatisPlus 三、MP常用配置3.1 设置表映射规则3.2 设置主键生成策略3.3 设置字段映射关系3.4 设置字段和列名的驼峰映射3.5 日志 四、基本使用4.1 增加&#xff08;插入&#xff09;…

TF卡/U盘扩容

1. 问题 在使用大于镜像、对TF卡/U盘烧录镜像以后&#xff0c;TF卡/U盘会出现一部分的空闲内存无法被使用&#xff0c;导致出现使用空间不足的报错&#xff0c;或运行大型项目不成功。 注意&#xff1a;本教程仅针对自行烧录镜像的用户&#xff0c;TF卡/U盘内如有出厂镜像则可…