LeetCode刷题---斐波那契数列模型

news2024/11/19 1:30:03

顾得泉:个人主页

个人专栏:《Linux操作系统》  《C/C++》  《LeedCode刷题》

键盘敲烂,年薪百万!


一、第N个泰波那契数

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

题目描述

泰波那契序列Tn定义如下:

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

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

示例1:

        输入:n=4

        输出:4

解释:

        T_3=0+1+1=2

        T_4=1+1+2=4

示例2:

        输入:n= 25

        输出:1389537

解法

1.状态表示:

        这道题可以「根据题目的要求」直接定义出状态表示:

        dp[i]表示:第i个泰波那契数的值。

2.状态转移方程:

        题目已经非常贴心的告诉我们了∶

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

3.初始化:

        从我们的递推公式可以看出,dp[i]在i = 0以及i = 1的时候是没有办法进行推导的,因为dp[-2]或dp[-1]不是一个有效的数据

        因此我们需要在填表之前,将0,1,2位置的值初始化

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

4.填表顺序:

        毫无疑问是「从左往右」

5.返回值:

        返回dp[n]的值

代码实现

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[0] = 0,dp[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];
    }
};

优化解法

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. 三步问题  

题目描述

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

示例1:

        输入:n=3

        输出:4

说明:有四种走法

示例2:

        输入:n=5

        输出:13

提示:

        n范围在[1,1000000]之间

解法

​1.状态表示

       这道题可以根据「经验+题目要求」直接定义出状态表示:dp[i]表示:到达i位置时,一共有多少种方法。

2.状态转移方程

       以i位置状态的最近的一步,来分情况讨论:

       如果dp[i]表示小孩上第1阶楼梯的所有方式,那么它应该等于所有上关步的方式之和:

             i. 上一步上一级台阶,dp[i] += dp[i - 1] 

             ii.上一步上两级台阶,dp[i] += dp[i - 2]

             iii.上一步上三级台阶,dp[i] += dp[i - 3]

       综上所述,dp[i] = dp[i - 1]+ dp[i - 2] +dp[i]

       需要注意的是,这道题目说,由于结果可能很大,需要对结果取模。

       在计算的时候,三个值全部加起来再取模,即(dp[i l+ dp[i - 2] + dp[i - 3])% MOD是不可取的,大家可以试验一下,取题目范围内最大值时,网站会报错signedinteger overflow。对于这类需要取模的问题,我们每计算一次(两个数相加/乘等),都需要取一次模。否则,万一发生了溢出,我们的答案就错了。

3.初始化

       从我们的递推公式可以看出,dp[i]在i = 0, i = 1以及i = 2的时候是没有办法进行推导的,因为dpL3]dp[-2]或dp[-1]不是一个有效的数据

       因此我们需要在填表之前,将1,2,3位置的值初始化

       根据题意,dp[1= 1, dp[2] = 2,dp[3] = 4

4.填表顺序

        毫无疑问是「从左往右」

5. 返回值

       返回dp[n]的值

代码实现

class Solution {
public:
    int waysToStep(int n) 
    {
        const int MOD = 1e9 + 7;
        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]) % MOD + dp[i-3]) % MOD;
        return dp[n];
    }
};

优化解法

class Solution {
public:
    int waysToStep(int n) 
    {
        const int MOD = 1e9 + 7;
        if(n == 1 || n == 2) 
            return n;
        if(n == 3) 
            return 4;
        int a = 1, b = 2, c = 4, d = 0;
        for(int i = 4;i <= n; i++)
        {   
            d = ((a + b) % MOD + c) % MOD;
            a = b;
            b = c;
            c = d;
        }
        return d;
    }
};

三、使用最小花费爬楼梯

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

题目描述

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

       你可以选择从下标为0或下标为1的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。

示例1:

        输入: cost = [10,15,20]

        输出:15

解释:

       你将从下标为1的台阶开始

       支付15,向上爬两个台阶,到达楼梯顶部,总花费为15

示例2:

        输入: cost =[1,100,1,1,1,100,1,1,100,1]

        输出:6

解释:

        你将从下标为0的台阶开始。

        支付1,向上爬两个台阶,到达下标为2的台阶。

        支付1,向上爬两个台阶,到达下标为4的合阶。

        支付1,向上爬两个台阶,到达下标为的合阶。

        支付1,向上爬一个台阶,到达下标为7的台阶。

        支付1,向上爬两个台阶,到达下标为9的台阶。

        支付1,向上爬一个合阶,到达楼梯顶部。

        总花费为6。

注意注意:

     在这道题中,数组内的每一个下标[o,n - 1]表示的都是楼层,而顶楼的位置其实是在n的位置! 

解法

​1.状态表示:

       这道题可以根据「经验+题目要求」直接定义出状态表示:

       以1位置为结尾,巴拉巴拉

       dp[i]表示:到达1位置时的最小花费。(注意:到达i位置的时候,i位置的钱不需要算上)

2.状态转移方程:

根据最近的一步,分情况讨论:

             先到达i - 1的位置,然后支付cost[i - 1]

             接下来走一步走到i位置:dp[i - 1]+ csot[i - 1] ;

             先到达i -2的位置,然后支付cost[i - 2]

             接下来走一步走到i位置:dp[i - 2]+ csot[i - 2]。

3.初始化:

       从我们的递推公式可以看出,我们需要先初始化i = 0,以及 i 1位置的值。容易得到dp[0] = dp[1] = 0,因为不需要任何花费,就可以直接站在第层和第层上。

4.填表顺序:

       根据「状态转移方程」可得,遍历的顺序是「从左往右」。

5.返回值:

       根据「状态表示以及题目要求」,需要返回dp[n]位置的值。

代码实现

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) 
    {
        int n = cost.size();
        vector<int> dp(n + 1);
        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];
    }
};

四 、解码方法

题目链接:91. 解码方法   

题目描述

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

        'A' -> "1"
        'B' -> "2"
        ...
        'Z' -> "26"

       要解码已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为:

  • "AAJF" ,将消息分组为 (1 1 10 6)
  • "KJF" ,将消息分组为 (11 10 6)

       注意,消息不能分组为  (1 11 06) ,因为 "06" 不能映射为 "F" ,这是由于 "6" 和 "06" 在映射中并不等价。

       给你一个只含数字的非空字符串 s ,请计算并返回解码方法的总数 。

       题目数据保证答案肯定是一个 32 位 的整数。

示例 1:

输入:s = "12"
输出:2
解释:它可以解码为"AB"(1 2)或者 "L"(12)。

示例 2:

输入:s = "226"
输出:3
解释:它可以解码为"BZ"(2 26),"VF"(22 6), 或者"BBF"(2 2 6) 。

示例 3:

输入:s = "06"
输出:0
解释:"06" 无法映射到"F",因为存在前导零("6" 和 "06" 并不等价)。

提示:

  • 1 <= s.length <= 100
  • s 只包含数字,并且可能包含前导零。

解法

​类似于斐波那契数列~

1.状态表示:

       根据以往的经验,对于大多数线性dp,我们经验上都是下以某个位置结束或者开始做文章,这里我们继续尝试「用i位置为结尾」结合「题目要求」来定义状态表示。

        dp[i]表示:字符串中[0,i]区间上,共有多少种编码方法。

2.状态转移方程:

        定义好状态表示,我们就可以分析i位置的dp值,如何由「前面」或者「后面」的信息推导出
来。关于i位置的编码状况,我们可以分为下面两种情况:

             i. 让i位置上的数单独解码成一个字母;

             ii.让i位置上的数与i - 1位置上的数结合,解码成一个字母。

下面我们就上面的两种解码情况,继续分析:

     让i位置上的数单独解码成一个字母,就存在「解码成功」和「解码失败」两种情况:

          i.解码成功:当i位置上的数在[1,9]之间的时候,说明1位置上的数是可以单独解码的,那么此时[0,i]区间上的解码方法应该等于[0, i - 1]区间上的解码方法。因为[0,i - 1]区间上的所有解码结果,后面填上一个 i位置解码后的字母就可以了。此时dp[i] = dp[i - 1] ;

          ii.解码失败:当i位置上的数是 0的时候,说明1位置上的数是不能单独解码的,那么此时[0,i]区间上不存在解码方法。因为1位置如果单独参与解码,但是解码失败了,那么前面做的努力就全部白费了。此时dp[i] = 0。

     让1位置上的数与i – 1位置上的数结合在一起,解码成一个字母,也存在「解码成功」和「解码失败」两种情况:

          i.解码成功:当结合的数在[10,26]之间的时候,说明([i - 1,i]两个位置是可以解码成功的,那么此时[0,i]区间上的解码方法应该等于[0,i - 2]区间上的解码方法,原因同上。此时的dp[i] = dp[i - 2] ;
          ii.解码失败:当结合的数在[0,9]和[27 , 99]之间的时候,说明两个位置结合后解码失败(这里一定要注意00 01 02 03 04......这几种情况),那么此时[0,i]区间上的解码方法就不存在了,原因依旧同上。此时dp[i] = 0。

       综上所述: dp[i]最终的结果应该是上面四种情况下,解码成功的两种的累加和(因为我们关心的是解码方法,既然解码失败,就不用加入到最终结果中去),因此可以得到状态转移方程

       ( dp[i]默认初始化为0) 

          i. 当s[i]上的数在[1,9]区间上时: dp[il t= dp[i - 1]

          ii.当 s[i - 1]与s[i]上的数结合后,在[10,26之间的时候:dp[i] +=dp[i - 2] ;

       如果上述两个判断都不成立,说明没有解码方法,dp[i]就是默认值0。

3.初始化:

方法一(直接初始化)∶

     由于可能要用到i - 1以及个位置上的dp值,因此要先初始化「前两个位置」。初始化 dp[o]:

         i. 当s[0] == '0'时,没有编码方法,结果dp[0] = 0 ;

         ii.当s[0] != '0'时,能编码成功,dp[0] = 1

初始化 dp[1j:

         i. 当s[1在[1,9]之间时,能单独编码,此时dp[1] += dp[0](原因同上,dp[1]默认为0)

         ii.当 s[0]与s[1]结合后的数在([10,26]之间时,说明在前两个字符中,又有一种编码方式,此时dp[1] += 1

方法二(添加辅助位置初始化)∶

     可以在最前面加上一个辅助结点,帮助我们初始化。使用这种技巧要注意两个点:

         i.辅助结点里面的值要保证后续填表是正确的;

         ii.下标的映射关系

4.填表顺序:

       毫无疑问是「从左往右」

5.返回值:

       应该返回dp[n - 1]的值,表示在[o,n - 1]区间上的编码方法

代码实现---方法一

class Solution {
public:
    int numDecodings(string s) 
    {
        int n = s.size();
        vector<int> dp(n);
        dp[0] = s[0] != '0';

        if(n == 1) 
            return dp[0];

        if(s[0] != '0' && s[1] != '0') 
            dp[1] += 1;
        int t = (s[0] - '0') * 10 + s[1] - '0';
        if(t >= 10 && t <= 26) 
            dp[1] += 1;

        for(int i = 2; i <n; i++)
        {
            if(s[i] != '0') 
                dp[i] += dp[i-1];
            int t = (s[i-1] - '0') * 10 + s[i] - '0';
            if(t >= 10 && t <= 26) 
                dp[i] += dp[i-2];
        }
        return dp[n-1];
    }
};

代码实现---方法二

class Solution {
public:
    int numDecodings(string s) 
    {
        int n = s.size();
        vector<int> dp(n + 1);
        dp[0] = 1;
        dp[1] = s[1 - 1] != '0';


        for(int i = 2; i <= n; i++)
        {
            if(s[i-1] != '0') 
                dp[i] += dp[i-1];
            int t = (s[i-2] - '0') * 10 + s[i-1] - '0';
            if(t >= 10 && t <= 26) 
                dp[i] += dp[i-2];
        }
        return dp[n];
    }
};

结语:今日的刷题分享到这里就结束了,希望本篇文章的分享会对大家的学习带来些许帮助,如果大家有什么问题,欢迎大家在评论区留言~~~ 

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

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

相关文章

【SpringCloud原理】OpenFeign原来是这么基于Ribbon来实现负载均衡的

大家好&#xff0c;本文我将继续来剖析SpringCloud中负载均衡组件Ribbon的源码。本来我是打算接着OpenFeign动态代理生成文章直接讲Feign是如何整合Ribbon的&#xff0c;但是文章写了一半发现&#xff0c;如果不把Ribbon好好讲清楚&#xff0c;那么有些Ribbon的细节理解起来就很…

Pycharm2020.3.5激活方式

激活插件链接&#xff1a;https://pan.baidu.com/s/1tPd7V4pKUx0Z6fSKumLjTQ 提取码&#xff1a;lr12 1.pycharm主界面点开设置如下&#xff1a; 2.点击 Plugins 然后依次点击&#xff1a;小齿轮->选择本地安装&#xff08;下图&#xff09; 3.找到存放插件的目录&#xf…

系统设计概念:生产 Web 应用的架构

在你使用的每个完美应用程序背后&#xff0c;都有一整套的架构、测试、监控和安全措施。今天&#xff0c;让我们来看看一个生产就绪应用程序的非常高层次的架构。 CI/CD 管道 我们的第一个关键领域是持续集成和持续部署——CI/CD 管道。 这确保我们的代码从存储库经过一系列测试…

用customize-cra+react-app-rewired配置less+css module

1. 安装 npm i less less-loader -D npm i customize-cra-less-loader -D2.添加配置项 //config-overrides.js const { override } require(customize-cra); const addLessLoader require("customize-cra-less-loader");module.exports {webpack: override(addL…

解决VS2019无法正常显示XAML设计界面问题

问题描述 当VS2019配置工程为x64模式时&#xff0c;打开工程中XAML页面可能出现如下错误提示&#xff0c;进而无法正常显示XAML设计界面。 There was an exception when loading the design time assembly C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\16.0_…

【云备份】热点管理模块

文章目录 整体思路概括热点管理实现构造函数Hotjudge ——热点判断RunModule ——运行模块 代码实现hot.hpp 整体思路概括 整体概括&#xff1a; 对服务器上备份的文件进行检测&#xff0c;那些文件长时间没有被访问&#xff0c;则认为是非热点文件 进行压缩存储&#xff0c;节…

基于UDP的网络聊天室

客户端 #include <myhead.h> //定义存储信息结构体 typedef struct _MSG {char code; //操作码&#xff1a;L表示登录C表示群聊S表示系统消息S表示退出char name[128]; char txt[256];}msg_t;//定义保存客户端网络信息的链表 typedef struct _ADDR {struct sockaddr_i…

【Springboot系列】SpringBoot整合Jpa

文章目录 前言&#xff1a;什么是JPA&#xff1f;JPA优缺点优点1.简化开发&#xff1a;2.高度抽象&#xff1a;3.跨数据库支持&#xff1a;4.自动化的事务管理&#xff1a; 缺点1.学习成本较高&#xff1a;2.性能问题&#xff1a;3.灵活性受限&#xff1a; 示例版本依赖代码Use…

VSCode 代码调试

断点调试&#xff08;debug&#xff09;&#xff1a; 指在程序的某一行设置一个断点&#xff0c;调试时&#xff0c;程序运行到这一行就会停住&#xff0c;然后你可以一步一步往下调试&#xff0c;调试过程中可以看各个变量当前的值&#xff0c;出错的话&#xff0c;调试到出错…

NSSCTF第14页(1)

[suctf 2019]checkin 利用了几种方式&#xff0c;发现都不行 1是修改mime类型&#xff0c;2是修改php标签为js标签&#xff0c;3是修改文件后缀 在试试用配置文件来上传 发现上传.user.ini文件成功 发现上传成功 上传的png图片 访问上传路径发现可以访问&#xff0c;上马成…

位运算算法【2】

文章目录 &#x1f377;371. 两整数之和&#x1f959;题目&#x1f345;算法原理&#x1f346;代码实现 &#x1f378;137. 只出现一次的数字 II&#x1f9c6;题目&#x1fad2;算法原理&#x1f954;代码实现 &#x1f379;面试题 17.19. 消失的两个数字&#x1f95a;题目&…

Android : GPS定位 获取当前位置—简单应用

示例图&#xff1a; MainActivity.java package com.example.mygpsapp;import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat;import android.Manif…

burp2023专业版,配置上游代理太难找

burpsuite2023专业版的工具栏与之前的版本不同的是&#xff0c;工具栏中没有了user options这一选项 但在通常的使用过程中&#xff0c;常用到配置上游代理。之前的版本呢&#xff0c;上游代理的配置都在user options选项中设置&#xff0c;user options选项还在工具栏中&#…

小航助学题库蓝桥杯题库c++选拔赛(23年8月)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09; 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;

【JS Promise, Promise.all 与 async/await用法详解】

目录 PromisePromise基本使用Promise可进行连续回调Promise回调可接受入参1.工作原理 async/await总结参考文档&#xff1a; 异步 let a 0setTimeout(() > {a 1}, 1000)console.log(a) // 0此时这个延迟就成为异步执行的了&#xff0c;a值还没有变1就被使用输出&#xff0…

【产品经理】AI在SaaS产品中的应用及挑战

随着ChatGPT大模型在全球的爆火&#xff0c;AI迅速在各个行业内&#xff0c;助力于各行业的效率提升。而SaaS领域&#xff0c;AI同样也大有可为。 AI&#xff08;人工智能&#xff0c;Artificial Intelligence的缩写&#xff09;近一年来一直处于舆论风口&#xff0c;随着ChatG…

NX二次开发UF_CURVE_create_bridge_feature 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_create_bridge_feature Defined in: uf_curve.h int UF_CURVE_create_bridge_feature(UF_CURVE_bridge_data_p_t bridge_data, tag_p_t bridge_feature ) overview 概述 …

在零信任架构下的API安全与滥用防护(上)

引言 在当今数字化的浪潮中&#xff0c;应用程序编程接口&#xff08;API&#xff09;的战略重要性愈发凸显。API不仅仅是现代软件和互联网服务之间沟通的桥梁&#xff0c;更是企业价值创造的核心。随着API的快速发展和广泛应用&#xff0c;安全问题随之而来&#xff0c;其中A…

保障海外业务发展,Coremail提供高效安全的海外通邮服务

11月22日&#xff0c;Coremail举办《全球通邮&#xff1a;如何保障安全、快捷的海外中继服务》直播分享会&#xff0c;直播会上Coremail安全团队和直播嘉宾复旦大学校园信息化办公室徐艺扬老师就海外中继服务进行了深度分享。 ​ 海外通邮困难重重 境外垃圾邮件数量居高不下…

【Spring Boot 源码学习】BootstrapRegistryInitializer 详解

Spring Boot 源码学习系列 BootstrapRegistryInitializer 详解 引言往期内容主要内容1. 初识 BootstrapRegistryInitializer2. 加载 BootstrapRegistryInitializer3. BootstrapRegistryInitializer 的初始化 总结 引言 书接前文《初识 SpringApplication》&#xff0c;我们从 …