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

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

📝前言说明:

  • 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分
  • 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
  • 文章中的理解仅为个人理解。如有错误,感谢纠错
🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础python入门基础C++学习笔记Linux
🎀ZEEKLOG主页 愚润泽

你可以点击下方链接,进行不同专题的动态规划的学习

点击链接开始学习
斐波那契数列模型路径问题
简单多状态(一)简单多状态(二)
子数组系列(一)子数组系列(二)
子序列问题(一)子序列问题(二)
回文串(一)回文串(二)
两个数组dp问题(一)两个数组的dp问题(二)
01背包问题完全背包
二维的背包问题其他

题单汇总链接:点击 → 题单汇总

题目

动态规划要点

动态规划的核心思想是将问题分解为相互关联的子问题,通过求解子问题并利用子问题的解来构造原问题的解,同时避免重复计算子问题。
动态规划分成五大要点,这五点都和要创建的dp表有关,dp表可以帮助我们快速得到题目答案:

  • 状态表示(重点)
    • 是什么?:dp[i]的值所代表的含义
    • 怎么得到?(对于线性的dp问题:经验 + 题目分析)
      • 经验:以某一个位置为结尾 / 为开头,怎样怎样
      • 再根据题目要求分析,发现子问题(填充,怎样怎样)
  • 状态转移方程(难点)
    • 即:dp[i]等于什么
  • 初始化
    • 初始化,并且保证填表的时候不越界
  • 填表顺序
  • 返回值
    • 根据题目要求,通过状态表示得到

空间优化(这个属于在能解决问题的基础上,进行算法优化了,不是我们前期的目标)
但是第1137 讲一下

1137. 第 N 个泰波那契数

题目链接:https://leetcode.cn/problems/n-th-tribonacci-number/description/

在这里插入图片描述

动态规划第一题,好好捋一下思路。

优质解

思路:

  • 状态表示:dp[i]表示第 i 个泰波那契数
  • 状态转移方程:dp[i] = dp[i - 3] + dp[i - 2] + dp[i - 1]
  • 初始化:dp[0] = 0; dp[1] = 1; dp[2] = 1
  • 填表顺序:从左往右
  • 返回值:dp[n]

代码:

classSolution{public:inttribonacci(int n){// 处理特殊情况if(n ==0)return0;if(n ==1|| n ==2)return1; vector<int>dp(n +1); dp[0]=0; dp[1]=1; dp[2]=1;// 初始化for(int i =3; i <= n; i++) dp[i]= dp[i -3]+ dp[i -2]+ dp[i -1];// 从左往右填表return dp[n];}};

时间复杂度:
空间复杂度:

本题的空间优化:
利用滚动数组,只记录前三个数的值(因为计算第 i 个数,只需要前三个数的值)

在这里插入图片描述


优化后的代码:

classSolution{public:inttribonacci(int n){// 处理特殊情况if(n ==0)return0;if(n ==1|| n ==2)return1;int a =0, b =1, c =1, ans =0;// 初始化for(int i =0; i <= n -3; i++){ ans = a + b + c; a = b; b = c; c = ans;}return ans;}};

面试题 08.01. 三步问题

题目链接:https://leetcode.cn/problems/three-steps-problem-lcci/description/

在这里插入图片描述

优质解

思路:

  • 状态表示:dp[i]表示:到第 i 个台阶的总方法数
  • 状态转移方程:
    • 首先,我们要搞清楚:只要有一步不同就是不同方案
    • 那么,假如此时在 i 位置,则从i - 3、i - 2、i - 1都可以到 位置i
      • i - 3i:直接走三步(一种方法),注意,这里不能选择走一步和两步,一维会走到i - 2i - 1上,这时候就不是不同方案了
      • i - 2i:直接走两步(一种方法)
      • i - 1i:走一步(一种走法,也就是说:最后一步如果这么走,那其实方法的总数就等于dp[i - 1]
    • 方程:dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]
  • 初始化:dp[1] = 1; dp[2] = 2; dp[3] = 4;
  • 填表顺序:从左往右,线性的
  • 返回值:dp[n]

代码:

classSolution{public:intwaysToStep(int n){// 处理边界情况if(n ==1|| n ==2)return n;if(n ==3)return4; 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])%1000000007+ dp[i -3])%1000000007;// 每次相加都% 防止溢出return dp[n];}};

时间复杂度:O(n)
空间复杂度:O(n)


746. 使用最小花费爬楼梯

题目链接:https://leetcode.cn/problems/min-cost-climbing-stairs/description/

在这里插入图片描述

个人解

思路:

  • 状态表示:dp[i] 爬到第 i 个台阶的最小费用
  • 状态转移方程:dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
  • 初始化:dp[0] = 0; dp[1] = 0;
  • 填表顺序:从左往右
  • 返回值:dp[n]

用时:3:00
屎山代码:

classSolution{public:intminCostClimbingStairs(vector<int>& cost){int n = cost.size(); vector<int>dp(n +1); dp[0]=0; dp[1]=0;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];}};

时间复杂度:O(n)
空间复杂度:O(n)


91. 解码方法

题目链接:https://leetcode.cn/problems/decode-ways/description/

在这里插入图片描述

个人解

思路:

 // 状态表示 dp[i]: 前 i 个字符能凑成的组合总数 // 状态转移方程(只有能和其他数组合的时候,才有可能有新组): // dp[i] = dp[i - 1],当:s[i] 属于[1, 9],且s[i - 1]和s[i]组合不能成 // dp[i] = dp[i - 1] + 1 当:s[i] 属于[1, 9],且s[i - 1]和s[i]组合能成 // 特殊判断,s[i] == '0' 的情况,如果能和s[i - 1]组成,则dp[i] = dp[i - 1],如果不能组成则:不是合法编码 // 初始化: 如果s[0] 属于 [1, 9],则dp[0] == 1; // 填表顺序: 从左往右 // 返回值: dp[n] 

用时:20:00
屎山代码(通过237 / 269,但是数量的增加不是简单的+1关系,我没找到正确关系),以下为未通过的错误代码:

classSolution{public:intnumDecodings(string s){if(s[0]=='0')return0;int n = s.size(); vector<int>dp(n); dp[0]=1;for(int i =1; i < n; i++){int numi = s[i]-'0';// 字符转数字int numj = s[i -1]-'0';if(numi ==0)// 对 0 特殊处理if(numj <1|| numj >2)return0;// 不能和前面的数组合else dp[i]= dp[i -1];elseif((numj !=0&& numj *10+ numi <=26)&&!(i +1< n && s[i +1]=='0')){ dp[i]= dp[i -1]+1;}else dp[i]= dp[i -1];}return dp[n -1];}};

优质解

思路(类似爬楼梯):

  • 状态转移方程:当能和前面的数组合时,dp[i] = dp[i - 1] + dp[i - 2],当前位属于 1-9 时,可+ dp[i - 1],能和前面的数组成的时候,可+ dp[i - 2]
  • 根本不用特殊处理 0,因为0的结果也会体现在dp[i]

代码:

classSolution{public:intnumDecodings(string s){int n = s.size(); vector<int>dp(n);// 创建⼀个 dp表// 初始化前两个位置 dp[0]= s[0]!='0';if(n ==1)return dp[0];// 处理边界情况if(s[1]<='9'&& s[1]>='1') dp[1]+= dp[0];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]<='9'&& s[i]>='1') 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];}};

时间复杂度:O(n)
空间复杂度:O(n)


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

Read more

【前端】Vue 组件开发中的枚举值验证:从一个Type属性错误说起

【前端】Vue 组件开发中的枚举值验证:从一个Type属性错误说起

🌹欢迎来到《小5讲堂》🌹 🌹这是《小程序》系列文章,每篇文章将以博主理解的角度展开讲解。🌹 🌹温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!🌹 👨💻 作者简介 🏆 荣誉头衔:2024博客之星Top14 | ZEEKLOG博客专家 | 阿里云专家博主 🎤 经历:曾多次进行线下演讲,亦是 ZEEKLOG内容合伙人 以及 新星优秀导师 💡 信念:“帮助别人,成长自己!” 🚀 技术领域:深耕全栈,精通 .NET Core (C#)、Python、Java,熟悉主流数据库 🤝 欢迎交流:无论是基础概念还是进阶实战,都欢迎与我探讨! 目录 * 前言 * 解决过程 * 一、错误场景还原 * 1.1 错误发生的位置 * 1.2 常见的触发场景 * 二、深入理解 Vue

By Ne0inhk

Linux内核IRQ子系统:核心数据结构深度解析 (基于 Linux 6.6)

引言:中断处理的挑战与抽象 在复杂的现代计算系统中,硬件设备(如网卡、磁盘、键盘)通过中断信号来通知 CPU 有事件需要处理。然而,不同架构(x86, ARM)、不同总线(PCIe, USB)和不同控制器(GIC, APIC, 8259)的中断机制千差万别。如果每个驱动都直接与底层硬件打交道,内核将变得极其臃肿且难以维护。 Linux IRQ 子系统的诞生就是为了解决这一复杂性。它通过一套精巧的、分层的数据结构和接口,向上为设备驱动提供统一、简单的中断注册和管理 API(如 request_irq),向下则通过可插拔的“中断控制器驱动”来适配各种硬件。这套系统的核心就是我们今天要深入剖析的几大数据结构。 更多及时精彩的linux内核子系统分析,请关注VX公众号:linux内核漫游手册. 1. irq_desc - 中断描述符:中断世界的“户口本” 定义位置:

By Ne0inhk
从零开始学java--二叉树和哈希表

从零开始学java--二叉树和哈希表

数据结构基础 目录 数据结构基础 树 树形结构: 树的概念: 二叉树 概念: 两种特殊的二叉树: 二叉树的性质: 创建一个简单的二叉树: 二叉树的遍历 前序遍历: 中序遍历: 后序遍历: 层序遍历: 二叉查找树和平衡二叉树 二叉查找树: 平衡二叉树: 红黑树 哈希表 树 树形结构: 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点: 1. 有一个特殊的结点,称为根结点,根结点没有前驱结点。 2. 除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、......、Tm,其中每一个集合Ti (1 <= i

By Ne0inhk
AN-93双麦降噪远场拾音模块技术解析:从算法到落地的全维度突破

AN-93双麦降噪远场拾音模块技术解析:从算法到落地的全维度突破

在语音交互技术全面渗透的当下,远场拾音与噪声抑制能力成为衡量音频设备性能的核心指标。单麦方案受限于无法区分空间声源信息,难以应对复杂噪声环境;多麦方案则面临成本高、体积大、集成难度高的痛点。AN-93双麦降噪远场拾音模块凭借“双核DSP+专属算法”的核心架构,在双麦硬件基础上实现了30-36dB的深度降噪与30cm-700cm的广域拾音,兼顾性能、成本与集成灵活性,为全场景音频设备升级提供了最优技术路径。本文将从技术原理、硬件设计、算法优化、性能验证及工程适配五个维度,深度解析AN-93的技术优势与落地价值。 一、核心技术原理:双麦阵列的空间声学信号处理逻辑 AN-93的核心优势源于对双麦阵列空间信息的精准挖掘与高效利用。与单麦仅依赖时域/频域信号处理的降噪方式不同,双麦方案通过两个麦克风的空间间距形成声学基线,利用目标语音与噪声在空间传播中的相位差、幅度差特性,实现“空域滤波+时域降噪”的双重抑制效果,从根源上分离目标语音与干扰信号。 其核心处理流程可分为三步:首先,通过双麦阵列同步采集声学信号,利用短时傅里叶变换(STFT)将时域信号转换为频域信号,提取各频点的相位差与幅度

By Ne0inhk