动归专题——斐波纳契模型和路径问题

news2024/9/22 1:58:24

前提

本专题开始,注重整理与动态规划相关的题目,从简单的动归开始切入,慢慢掌握和练习动态规划这一重要的算法思想,部分相对复杂的题目会结合画图和代码分析去解释

一、第N个泰波纳契数列

1.链接

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

2.描述

3.思路

关于动态规划的题目,往后都是按照五步走的统一思路去进行分析

(1)状态表示

状态表示我们通常是根据经验加对具体题目的判断去设置的,通常的设置思路有:

以第i个位置为底,结合题目条件...

以第i个位置开始,结合题目条件...

...

本题状态表示:f(i)表示以i位置为底,泰波那契数列的值

(2)状态转移方程

状态方程的判断一般需要我们根据具体的题目条件去进行推导,这题目的方程式就是状态转移方程

f(i) = f(i-1)+ f(i-2) + f(i-3)

(3)初始化

初始化是为了确定边界条件,确定起始位置

f(0)= 0,f(1)= 1,f(2) = 1;

(4)填表顺序

写代码时,我们需要一个dp表,我们需要根据状态方程去判断填表顺序是从如何推导,本题的推导顺序很明显是从头往后推导记录

(5)返回值

确定返回的值,这个返回值根据题目不同,可能返回的不同,本题是返回dp[ n ]

4.参考代码

class Solution {
public:
    int tribonacci(int n) 
    {
        if(n == 0) return 0;
        if(n == 1 || n == 2) return 1;//考虑边界情况

        vector<int> dp(n+1);//创建dp表
        dp[0] = 0; dp[1] = 1; dp[2] = 1;//确定初始状态

        for(int i = 3;i<=n;i++)
        {
            dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
        }
        return dp[n];
    }
};

二、三步走问题

1.链接

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

2.描述

3.思路

(1)状态表示

以第n个台阶为底(一共有n个台阶),小孩一共有多少种走法

(2)状态转移方程

dp[ n ] = dp[n - 1] + dp[n - 2] + dp[n - 3]

(3)初始化

dp[1] = 1; dp[2] = 2; dp[3] = 4

(4)填表顺序

从左到右

(5)返回值

dp[ n ]

4.参考代码

class Solution {
public:
    const int num = 1e9+7;
    int waysToStep(int n) 
    {
        if(n == 1 || n == 2) return n;
        if(n == 3) return 4;
        vector<int> dp(n+1);
        dp[1] = 1; dp[2] = 2; dp[3] = 4;
        for(int i = 4;i <= n;i++)
        {
            dp[i] = ((dp[i-1] + dp[i-2])%num + dp[i-3])%num;
        }
        return dp[n];
    }
};

三、使用最小花费爬楼梯

1.链接

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

2.描述

3.思路

(1)状态表示

思路一:以i为结束,...

f(i)表示爬到第i层,花费最少的费用

思路二:以i为开始,...

f(i)表示从第i层开始,到楼顶需要花费最少的费用

(2)状态表示方程

思路一: f(i)= min ( f(i -1)+cost[i-1] ,f(i-2)+cost[i-2] )

思路二: f(i)= min( f(i+1) , f(i+2) ) + cost [ i ]

(3)初始化

思路一:f(0)= 0  ;   f( 1 ) = 0

思路二:f(n)= cost[ n ] ;   f(n-1)= cost[n-1]

(4)填表顺序

思路一:从左到右

思路二:从右到左

(5)返回值

思路一:dp[n] 

思路二:dp[0]

4.参考代码

思路一:

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) 
    {
        vector<int> dp(cost.size()+1);
        dp[0] = 0;
        dp[1] = 0;

        for(int i = 2;i<=cost.size();i++)
        {
            dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
        }
        return dp[cost.size()];
    }
};

思路二:

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) 
    {
        int n = cost.size()-1;
        vector<int> dp(n+1);
        dp[n] = cost[n];
        dp[n-1] = cost[n-1];

        for(int i = n-2;i>=0;i--)
        {
            dp[i] = min(dp[i+1],dp[i+2])+cost[i];
        }
        return min(dp[0],dp[1]);
    }
};

四、解码方法

1.链接

. - 力扣(LeetCode)

2.描述

3.思路

4.参考代码

class Solution 
{
public:
    int numDecodings(string s) 
    {
        int n = s.size();
        //由于dp[0]要作为辅助位置,因此映射关系整体向后移
        //也可以认为此刻dp[i]对应的就是从1开始往后数的第i个字母
        vector<int> dp(n+1,0);
        dp[0] = 1;
        dp[1] = s[0] != '0';
        for(int i = 2;i<=n;i++)
        {
            if(s[i-1]!='0')//i位置的数字单独解码成功
                dp[i]+=dp[i-1];

            int second = (s[i-2]-'0')*10+(s[i-1]-'0');
            if(second>=10 && second<=26)//第二种情况解码成功
                dp[i]+=dp[i-2];
        }
        return dp[n];
    }
};

五、不同路径

1.链接

62. 不同路径 - 力扣(LeetCode)

2.描述

3.思路

(1)状态表示

从左上角出发,走到[ i , j ]位置时一共有dp(i,j)种办法

(以[i,j]为结束,...)

(2)状态表示方程

(3)初始化

初始化需要考虑边界问题,通常我们会选择给路径多加上一层边框,然后对边框进行合理的赋值

(4)填表顺序

从左到右,从上到下,就是遍历二维数组的顺序

(5)返回值

dp[m,n]

4.参考代码

class Solution {
public:
    int uniquePaths(int m, int n) 
    {
        vector<vector<int>> dp(m+1,vector(n+1,0));
        dp[0][1] = 1;
        for(int i =1;i<=m;++i)
        {
            for(int j = 1; j<=n;++j)
            {
                dp[i][j] = dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[m][n];
    }
};

六、不同路径||

1.链接

63. 不同路径 II - 力扣(LeetCode)

2.描述

3.思路

(1)状态表示

dp[i,j] :  以[i,j]位置结束,一共有dp[i,j]种路线

(2)状态表示方程

(3)初始化

和上题的初始化一样,不过这里就需要注意映射关系了,在题目给的障碍表格中要注意映射关系

(4)填表顺序

从左上角到右下角

(5)返回值

dp[m,n]

4.参考代码

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) 
    {
        int m = obstacleGrid.size();
        int n = obstacleGrid[0].size();
        vector<vector<int>> dp(m+1,vector(n+1,0));
        dp[0][1] = 1;
        for(int i = 1;i<=m;i++)
        {
            for(int j = 1;j<=n;j++)
            {
                if(obstacleGrid[i-1][j-1] != 1)
                {
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
        }
        return dp[m][n];
    }
};

七、珠宝的最高价值

1.链接

LCR 166. 珠宝的最高价值 - 力扣(LeetCode)

2.描述

3.思路

(1)状态表示

dp[i,j] 表示 以[i,j]位置结束,所获得的最大珠宝价值

(2)状态表示方程

有了上面两题的经验,不难分析出,[i,j]位置获得的最大珠宝价值,会等于当前位置的珠宝价值加上max(dp[i-1,j],dp[i,j-1])

dp[i,j] = max(dp[i-1,j],dp[i,j-1])+frame[ i ][ j ] (实际代码中要注意具体映射位置)

(3)初始化

和前两题一样的初始化方式,但是本题中不需要对第一个位置进行赋值为1,因为此时dp记录的是珠宝的价值,因此起始是不需要赋值的,全部初始化为0即可

(4)填表顺序

从左上角到右下角

(5)返回值

return dp[m][n]

4.参考代码

class Solution {
public:
    int jewelleryValue(vector<vector<int>>& frame) 
    {
        int m = frame.size();
        int n = frame[0].size();
        vector<vector<int>> dp(m+1,vector(n+1,0));
        for(int i = 1;i<=m;i++)
        {
            for(int j = 1;j<=n;j++)
            {
                dp[i][j] = max(dp[i-1][j],dp[i][j-1])+frame[i-1][j-1];
            }
        }
        return dp[m][n];
    }
};

八、下降路径最小和

1.链接

931. 下降路径最小和 - 力扣(LeetCode)

2.描述

3.思路

(1)状态表示

这次我们换一个思路,“以i位置开始,...”

以当前位置[ i ][ j ] 开始,走到最底下的最小路径和为dp[ i ][ j ]

(2)状态表示方程

(3)初始化

我们通过题目可以看到,每次dp遍历选择时,最左边那一列和最右边那一列存在越界的问题,因此我们可以给左右两边各加上一列去解决边界越界的问题,同时由于题目计算的是最小路径和,辅助列相当于非法路径,我们可以给其赋值为最大值,即可保证dp不会选择非法路径,再往最后一行添加一行辅助行,实现最后一列dp的赋值

(4)填表顺序

从最后一行往上填表,从下到上,从左往右

(5)返回值

取第一行中最小值返回

4.参考代码

这种思路到这来在映射关系上会比较复杂,需要画图,这题是为了练习另一种思路,推荐使用:

以[i][j]位置结束,所需的最小路径和为dp[i][j]的思路会更好写代码

class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& matrix) 
    {
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<int>> dp(m+1,vector<int>(n+2,INT_MAX));
        //初始化
        for(int i = 0;i<=n+1;i++)
        {
            dp[m][i] = 0;
        }
        for(int i = m-1;i>=0;i--)
        {
            for(int j = 1;j<=n;j++)
            {
                dp[i][j] = min(min(dp[i+1][j-1],dp[i+1][j]),dp[i+1][j+1]) + matrix[i][j-1];
            }
        }
        int ret = dp[0][1];
        for(int i = 2;i<=n;i++)
        {
            ret = min(ret,dp[0][i]);
        }
        return ret;
    }
};

九、最小路径和

1.链接

64. 最小路径和 - 力扣(LeetCode)

2.描述

3.思路

(1)状态表示

以[i][j]位置为结束,最小的路径和为dp[i][j]

(2)状态表示方程

dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i][j]

(3)初始化

多加一行和一列的辅助行和辅助列,初始化为最大值,然后让dp[0][1] = 0,确保第一个左上角位置的路径值是正确的,最大值则是保证其他路径不会选择非法路径

(4)填表顺序

从左上角到右下角

(5)返回值

dp[m][n]

4.参考代码

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) 
    {
        int m = grid.size();
        int n = grid[0].size();
        vector<vector<int>> dp(m+1,vector<int>(n+1,INT_MAX));
        dp[0][1] = 0;
        for(int i = 1;i<=m;++i)
        {
            for(int j = 1;j<=n;j++)
            {
                dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i-1][j-1];
            }
        }
        return dp[m][n];
    }
};

十、地下城游戏

1.链接

174. 地下城游戏 - 力扣(LeetCode)

2.描述

3.思路

(1)状态表示

根据题意,这里若是使用以[i][j]位置结束的思路,则不能保证后续路程可以走完,要采用另一种思路

dp[i][j] : 以[ i ][ j ]位置开始,走到最后所需要消耗的最小健康值

(2)状态表示方程

dp[i][j] = min( dp[i+1][j],dp[i][j+1] ) - dungeon[ i ][ j ]

我们可以认为,某个位置的点数如果是正数则就是回血,可以减少消耗,若是负数则加上增加了消耗,并且,还要考虑到消耗不能为负数,负数意味着有一个大血包,但勇士不能从0血以下开始走,当遇到大血包时,我们认为该点走到结尾的消耗为0

(3)初始化

我们需要辅助层去保证不越界的问题,dp起始位置是在末尾(右下角),为了不越界,我们需要给辅助层初始化为最大值,而为了让第一个dp填对,我们要让其相邻的其中一个为0(dp[i+1][j] =0)

(4)填表顺序

从右下角开始,从右往左,从下往上

(5)返回值

return dp[0][0]+1;

4.参考代码

class Solution {
public:
    int calculateMinimumHP(vector<vector<int>>& dungeon) 
    {
        int m = dungeon.size();
        int n = dungeon[0].size();
        vector<vector<int>> dp(m+1,vector<int>(n+1,INT_MAX));
        dp[m][n-1] = 0;

        for(int i = m-1;i>=0;--i)
        {
            for(int j = n-1;j>=0;--j)
            {
                dp[i][j] = min(dp[i+1][j],dp[i][j+1]) - dungeon[i][j];
                dp[i][j] = max(0,dp[i][j]);
            }
        }
        return dp[0][0] + 1;
    }
};

总结

本篇总结了关于动态规划的一些题目,斐波那契数列类型的和路径问题相关的动态规划经典题目

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

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

相关文章

使用EasyYapi插件简化导出yapi接口

安装 &#xff1a; 关键配置&#xff1a; 其中的token在这里拿&#xff1a; 使用&#xff1a; 导出当前Controller下的所有api&#xff1a;使用下图命令可仅导出指定的api: 附&#xff1a;配置部分参考了idea&#xff1a;使用easyYapi插件导出yapi接口

Vue-常用UI组件库

文章目录 一、移动端常用UI组件库二、PC端常用UI组件库三、elementUI基本使用四、element-UI按需引入 一、移动端常用UI组件库 Vant https://youzan.github.io/vant Cube Ul https://didi.github.io/cube-ui Mint UI http://mint-ai.github.io 二、PC端常用UI组件库 Element…

欢迎永创自动化设备2024第七届世界燕窝及天然滋补品博览会

参展企业介绍 深圳市永创自动化设备有限公司&#xff0c;联系客户经理 同微信。公司位于创新之城深圳市宝安区美丽的凤凰山脚下&#xff0c;是杭州永创智能设备股份有限公司深圳分公司&#xff0c;总部位于杭州市高新技术产业园&#xff0c;上交所主板上市。目前拥有科研人员五…

window下迁移SVN仓库到新的windows服务器

一、背景 一个基于 Windows 的 SVN 服务器&#xff0c;用于管理团队的代码库。该 SVN 仓库托管着公司的软件项目&#xff0c;包括多个分支和版本的代码。我们的团队规模约为 50 人&#xff0c;分布在不同的地理位置&#xff0c;他们都依赖 SVN 仓库来进行代码版本控制和协作开…

视频素材网站哪个比较好?8个优质视频素材软件app推荐

在探索那些能够让视频作品焕发生机的宝藏网站时&#xff0c;一个好的短视频素材库不仅能提升作品的视觉效果&#xff0c;还能赋予作品更深的情感层次。为了帮助你更好地寻找到这些珍贵的资源&#xff0c;以下是一系列精选的视频素材网站&#xff0c;全面支持你的视频创作需求。…

眼观百遍,不如手敲一遍

眼观百遍&#xff0c;不如手敲一遍 Repetitive Viewing Cannot Surpass Hands-on Typing 在现代教育体系中&#xff0c;编程已成为一项基础而关键的技能。伴随着各种便捷的工具和在线资源的普及&#xff0c;获取并复制代码变得前所未有地容易。然而&#xff0c;在这种趋势下&am…

canvas画图历史记录展示

提示&#xff1a;canvas画图历史记录展示 文章目录 前言一、画图历史记录展示总结 前言 一、画图历史记录展示 test.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" con…

RHCE:请给openlab搭建web

1.关闭所有安全软件已经防火墙 2.安装所需软件 3.在Windows 文件中进行DNS映射 C:\Windows\System32\drivers\etc\hosts 文件进 行DNS 映射 4.创建www.openlab.com网站 5.创建教学资料子网站 6.创建学生信息子网站 进行验证 7.创建缴费子网站

荟萃分析R Meta-Analyses 1

参考&#xff1a;Harrer, M.、Cuijpers, P.、Furukawa, TA 和 Ebert, DD (2021)。 使用 R 进行荟萃分析&#xff1a;实践指南。佛罗里达州博卡拉顿和伦敦&#xff1a;Chapman & Hall/CRC Press。 ISBN 978-0-367-61007-4。 1.1什么是荟萃分析&#xff1f; 它的创始人之一 G…

Airflow【部署 01】调度和监控工作流工具Airflow官网Quick Start实操(一篇学会部署Airflow)

Airflow官网Quick Start实操 1.环境变量设置2.使用约束文件进行安装3.启动单机版3.1 快速启动3.2 分步骤启动3.3 启动后3.4 服务启动停止脚本 4.访问4.1 登录4.2 测试 来自官网的介绍&#xff1a; https://airflow.apache.org/ Airflow™是一个由社区创建的平台&#xff0c;以…

网络爬虫基本知识

什么是网络爬虫 网络爬虫&#xff08;Web crawler&#xff09;是一种自动化程序&#xff0c;用于在互联网上收集信息。它可以通过扫描和解析网页的超链接&#xff0c;自动访问网页并抓取所需的数据。网络爬虫常用于搜索引擎和数据采集工具中。 作用 通过有效的爬虫手段批量采…

SpringBoot 三种拦截http请求方式Filter,Interceptor和AOP

1 Filter Filter常被叫做过滤器&#xff0c;filter的调用周期大致如下 也就是说filter在servlet之前&#xff0c;没有办法在filter中获取springboot中的java bean对象。 Filter生命周期方法 init:在服务器启动后&#xff0c;会创建Filter对象&#xff0c;然后调用init方法。…

私人健身与教练预约管理系统设计与实现|SpringBoot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;…

电脑如何一键修复所有dll缺失,几种修复dll文件丢失的方法

修复所有DLL&#xff08;动态链接库&#xff09;文件缺失的问题通常不可能通过单一的"一键修复"按钮来实现&#xff0c;因为DLL文件缺失可能由各种不同的原因导致&#xff0c;比如应用程序安装不正确、病毒感染、或系统文件损坏等。 使用内置的系统文件检查器&#x…

Axure RP 8中文---快速原型设计工具,一站式解决方案

Axure RP 8是一款专业的快速原型设计工具&#xff0c;以其直观易用的界面和丰富的功能受到广大用户的青睐。它支持用户通过拖放操作快速创建交互式原型&#xff0c;包括线框图、流程图等&#xff0c;并具备高保真度的设计能力。Axure RP 8还提供了团队协作和共享功能&#xff0…

3分钟教你弄懂【01背包问题】

背包问题 介绍 将有限物品按找最大价值装进有限体积的背包中去 核心步骤 1.确定状态表示 2.确定边界和遍历顺序 3.找到状态转移方程 先上 Coding #include <iostream> using namespace std;const int N 300; int itemSize[N]; //每件物品的大小&#xff08;体积…

推荐一款电子翻页书制作软件

随着数字化时代的到来&#xff0c;电子书籍越来越受到人们的喜爱。而一款优秀的电子翻页书制作软件&#xff0c;则能够帮助你轻松制作出专业级的电子书&#xff0c;让你的阅读体验更加丰富多彩。 今天&#xff0c;我们就来为大家推荐一款优秀的电子翻页书制作软件——FLBOOK在线…

【QT入门】 Qt代码创建布局之栅格布局详解

往期回顾&#xff1a; 【QT入门】 Qt自定义信号后跨线程发送信号-CSDN博客 【QT入门】 Qt内存管理机制详解-CSDN博客 【QT入门】 Qt代码创建布局之水平布局、竖直布局详解-CSDN博客 【QT入门】 Qt代码创建布局之栅格布局详解 一、什么是栅格布局 所谓栅格布局&#xff0c;就是…

vue动态渲染本地路径图片不显示的解决方案,v-fro 渲染本地图片路径不显示

1、第一种解决方法 如果直接使用本地路径渲染是渲染不出来的&#xff0c;因为这种情况下渲染时会发送网络请求加你的本地地址所以渲染不出来。 这样怎么能找到路径&#xff1f;解决方案如下 // 渲染正常渲染即可 <div v-for"(item, index) in imgPath" :key&quo…

Python时间

UTC ~ 北京时间 【差8小时】 格式化日期时间为字符串:strftime 时间戳-1970.1.1到现在的秒数:time.time() AttributeError: partially initialized module ‘datetime’ has no attribute ‘fromtimestamp’ (most likely due to a circular import) 改正&#xff1a;文件名和…