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

国产FPGA开发实战:紫光同创编程软件中的约束文件详解与常见问题 本文详细解析了紫光同创FPGA编程软件中约束文件的关键配置技巧与常见问题。通过基础架构解析、时钟约束实践、物理约束调控及典型问题排查指南,帮助开发者高效掌握国产FPGA开发中的约束文件应用,提升开发效率与设计稳定性。 阅读详情

系列文章目录

leetcode - 双指针问题_leetcode双指针题目-优快云博客

leetcode - 滑动窗口问题集_leetcode 滑动窗口-优快云博客

高效掌握二分查找:从基础到进阶-优快云博客

leetcode - 前缀和_前缀和的题目-优快云博客


目录

系列文章目录

前言

1、题1 第 N 个泰波那契数 :

解法一:动态规划

参考代码:

解法二:空间优化版本

参考代码:

2、题2 三步问题:

解法: 动态规划

参考代码:

3、题3 使用最小花费爬楼梯:

解法一:动态规划(以某一个位置为结尾)

参考代码:

解法二:动态规划(以某一个位置为开头)

参考代码:

4、题4 解码方法:

解法:动态规划

参考代码:

优化参考代码:

总结

leetcode - 前缀和_前缀和的题目-优快云博客


前言

路漫漫其修远兮,吾将上下而求索;


大家可以先尝试自己做一下喔~

斐波那契数列模型 

  1. 1137. 第 N 个泰波那契数 - 力扣(LeetCode)
  2. 面试题 08.01. 三步问题 - 力扣(LeetCode)
  3. 746. 使用最小花费爬楼梯 - 力扣(LeetCode)
  4. 91. 解码方法 - 力扣(LeetCode)

1、题1 第 N 个泰波那契数 :

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

思考:

可以将泰波那契数看作是斐波那契数的加强版;

根据题意可知第n个泰波那契等于其前三个泰波那契数之和;

解法一:动态规划

动态规划的做题流程,一般会定义一个dp 表(dp 表通常是一个一维数组或者二维数组);一维数组的情况:先创建一个一维数组,该数组通常被称为dp 表,接下来就是填dp 表,其中的某一个值可能就是最后的结果;

我们可以使用动态规划来解决这道题,五个步骤:

1、确定一个动态表达式

2、根据该动态表达式来推导状态转移方程

3、初始化

4、填表顺序

5、返回值

a、状态表示

Q1: 什么是状态表示?

  • dp 表中某一个位置所代表的含义;eg.dp[0] 存了一个值a,那么值a 便会代表一个特殊的含义,其中此含义就是状态表示;

Q2:状态表示是怎么样来的?

一般有三种方式可以来确定:

  • 1、题目怎么要求,我们就怎么定义状态表示
  • 2、经验 + 题目要求
  • 3、分析题目的过程中发现重复的子问题(再将重复的子问题抽象为状态表达式)

注:在本题中可以直接按照题干的要求去定义一个状态表示;本题的目标:返回第n个泰波那契数;

我们可以搞一个dp 表,让dp[0] 表示第0个泰波那契数,dp[1] 表示第1个泰波那契数……dp[i] 表示第i 个泰波那契数……我们只需要返回第n 个泰波那契数,即返回 dp[n];

b、状态转移方程

在本题中,我们需要思考的是:dp[i] 怎么求来? 

推导状态转移方程:1、用之前或者之后的状态推导得到dp[i] 的值 2、根据最近的一步来划分问题

本题十分明显由可得:Tn = Tn-1 + Tn-2 + Tn-3 ;故而本题的状态转移方程为:dp[i] = dp[i-1] + dp[i-2] + dp[i-3];

c、初始化

初始化的含义:保证填dp表(根据状态转移方程来调表)的时候不会发生越界;

Q1:为什么要保证不越界?

  • 倘若用此处的状态转移方程:dp[i] = dp[i-1] + dp[i-2] + dp[i-3]; 直接填表,那么 dp[0] = dp[-1] + dp[-2] + dp[-3] ,而 dp[-1] ,dp[-2] ,dp[-3] 就是越界访问;本题中的dp[0] 、dp[1]、dp[2]使用状态转移方程的时候均会发越界,所以这三个值需要单独进行初始化;而如何初始化取决于题干;

在本题中:

d、填表顺序

Q:为什么要研究填表顺序?

  • 为保证填写当前状态的时候所需要的状态已经计算好了;

在本题中,因为dp[i] = dp[i-1] + dp[i-2] + dp[i-3],即填表的时候需要借助于其前三个数据,所以填表顺序为从左往右;

d、返回值

返回结果: 结合题目要求+状态表示

本题干:,所以我们返回 dp[n] 即可;

参考代码:

    int tribonacci(int n) 
    {
        //边界情况处理
        if(n==0) return 0;
        else if(n==1 || n==2) return 1;
        //创建一维dp
        //状态表示:dp[i]表示第i个泰波那契数
        //状态转移方程:dp[i] = dp[i-1] + dp[i-2] + dp[i-3]
        //初始化: dp[0]= 0 , dp[1] =1, dp[2] = 1; 
        //填表顺序: 从左往右
        //返回值:dp[n]
        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-1] + dp[i-2] + dp[i-3];
        }
        //返回结果
        return dp[n];
    }

解法二:空间优化版本

注:此处空间优化的技巧只会在这道题以及接下来的背包问题中可用;

关于动态规划的空间优化,一般都是用流动数组的形式来优化;可以将时间复杂度为O(N^2)的动态规划优化成时间复杂度为O(N),将时间复杂度为O(N)的动态规划优化成时间复杂度为O(1);

可以发现,在求某一状态时,仅需要该状态前三个状态就可以求得到本状态;当我们依次从左往右求dp[i] 的时候,dp数组中太靠前的数据反而用不到,显然用不到的数据可以省去的。仅用该数组中有效的若干个状态便可以解决,像这样的情况,我们都可以用滚动数组来解决;创建三个变量进行”流动“,以维护所求状态的前三个状态;

Q:明明是利用变量在滚动的,为什么叫做”滚动数组“?

”滚动数组“只是一个名字而已,取这个名称只是为了统一叫法;

注:三个变量,在实现的时候还可以定义为 int[3] 的数组,但是我们没有必要这么做,因为这样实现起来有点麻烦还没有用三个变量来实现得“利落”;

图解如下:

细节问题:

赋值时的方向问题,是从左向右赋值还是从右往左赋值呢?

所以应该选择从左往右赋值;

参考代码:

    int tribonacci(int n) 
    {
        if(n==0) return 0;
        else 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;
    }

2、题2 三步问题:

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

注:1000000007 可以写作 1e9+7

解法: 动态规划

动态规划的五个步骤:

1、确定状态表示

2、根据该状态表示确定状态转移方程

3、初始化(以确保在填表的时候不会越界)

4、确实填表顺序

5、返回值

1、状态表示

一般有三种方式可以来确定状态表示:

  • 1、题目怎么要求,我们就怎么定义状态表示
  • 2、经验 + 题目要求
  • 3、分析题目的过程中发现重复的子问题(再将重复的子问题抽象为状态表达式)

在推导此题的时候发现本题是一个线性dp 模型,求本题的状态表示可以先根据我们的 经验(以 i 位置为结尾) + 题目要求(计算到达第i 个台阶的方案数);

状态表示:dp[i] 表示到第 i 个位置时,一共有多少种方法;

2、状态转移方程

推导状态转移方程:1、用之前或者之后的状态推导得到dp[i] 的值 2、根据最近的一步来划分问题

经验:想办法让i 位置之前或者之后的状态来表示 dp[i] ;

从左往右到达 i 位置有三种情况:

dp[i] 分三种情况来讨论:

从(i-3) 这个位置跳三个台阶 到 i 位置上,首先就需要先到 (i-3) 这个位置上;假设到 (i-3) 这个位置上有 x 种方法,那么在到 (i-3)的方法数上这一步就是(i-3)->i 的方法数,即从 (i-3)->i 的方法数是 0->(i->3) 方法数 x ;

而从 0->(i-3) 位置的方法数为dp[i-3]

同理:

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

3、初始化

初始化的目的:保证填dp表(根据状态转移方程来调表)的时候不会发生越界;

在填dp[1] dp[2] dp[3] 的时候由于下标相减,会访问到 -1,-2,-3 下标的非法空间,为了避免越界访问的出现,此处需要初始化dp[1] dp[2] dp[3];

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

4、填表顺序

在本题中,只有将dp 前面的数据算出来了以后才可以算后面的,故而填表顺序为从左往右

5、返回值;

结合题干要求:,所以返回值为dp[n]

参考代码:

    int waysToStep(int n) 
    {
        //创建一维数组dp
        //状态表示: dp[i]到第i 阶台阶的方法数 状态转移方程:dp[i] = dp[i-1]+d[i-2] +dp[i-3]
        //初始化:dp[1] = 1, dp[2] = 2, dp[3] = 4
        //填表顺序:从左往右  返回值 ;dp[n]
        //边界情况处理
        const int MOD = 1e9+7;

        if(n==1 || n==2) return n;
        else if(n==3) return 4;
        //dp
        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];
    }

3、题3 使用最小花费爬楼梯:

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

首先我们需要明确题意:我们可以向上爬一阶也可以向上爬两步,但是需要支付从第i 个台阶向上爬的费用;我们需要计算得到到达楼梯顶部的最低花费;而我们选择开始,可以从下标为0的台阶开始,也可以从下标为1的台阶开始爬;

首先我们需要弄清楚的是,楼顶在什么地方?

先观察一下例子:

所以我们的楼顶为,最后一个数据的下一个位置;

解法一:动态规划(以某一个位置为结尾)

动态规划的五个步骤

1、确定一个状态表达式

2、根据该动态表达式来推导状态转移方程

3、初始化

4、填表顺序

5、返回值

1、状态表示

一般有三种方式可以来确定状态表示:

  • 1、题目怎么要求,我们就怎么定义状态表示
  • 2、经验 + 题目要求
  • 3、分析题目的过程中发现重复的子问题(再将重复的子问题抽象为状态表达式)

根据经验 + 题干要求

注:经验:像一维数组dp 一般分为两种,一种是以某一个位置为结尾;一种是以某一个位置为开头;

因为本题要找到达楼顶的最小花费,那么以i位置为结尾就相当于到达了第 i 个位置的最小花费;

那么dp[i] : 到达 i 位置的最小花费

2、状态转移方程

推导状态转移方程:1、用之前或者之后的状态推导得到dp[i] 的值 2、根据最近的一步来划分问题

根据题意,我们需要从前往后走,也就是说倘若我们要到达 i 位置就需要分为两种情况:

在本题中,到达哪一个台阶就需要支付相应的费用,如下:

到达 i 台阶有两种方式,我们选择花费最小的就可以了; 

而对于先达到 (i-1) 位置,再走一步到达 i 位置,就需要我们先计算出走到 (i-1) 位置上的最小花费再加上 (i-1) 上的花费就是到达 i 的费用;--> dp[i] = dp[i-1] + cost[i-1];

而对于先到达 (i-2) 位置,再走两步到达 i 位置,需要我们先计算出走到 (i-2) 位置上的最小花费,再加上 (i-2) 上的花费就是到达 i 的费用; --> dp[i] = dp[i-2] + cost[i-2];

综上:dp[i] = min(dp[i-1]+cost[i-1] , dp[i-2] + cost[i-2]);

很多dp 问题均是可以利用这种方式来推导出状态转移方程:

主线(引导我们推导状态转移方程的主线):用之前或者之后的状态来推导dp[i] 的值,其中状态转移的时候很好的经验:根据最近的一步来划分问题;(可以分情况)

3、初始化

初始化的目的:保证填dp表(根据状态转移方程来调表)的时候不会发生越界;

因为状态转移方程:dp[i] = min(dp[i-1]+cost[i-1] , dp[i-2] + cost[i-2]); 若 i 为0、1则就会发生越界访问,所以需要初始化 dp[0],dp[1] ;

即 dp[0] = 0 , dp[1] = 0;

4、填表顺序

填表顺序的确定是为了保证我们在填dp[i] 这个数的时候,dp[i-1] 以及 dp[i-2] 已经被计算出来了,那么填表顺序就是:从左往右;

5、返回值

根据题目要求:,所以我们返回 dp[n] 就可以了;

参考代码:

    int minCostClimbingStairs(vector<int>& cost) 
    {
        int n = cost.size();
        //创建一维数组dp
        //状态表示: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]
        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];
    }

解法二:动态规划(以某一个位置为开头)

解法一是以某一个位置为结尾,我们还可以以某一个位置为开头;

同样的,五个步骤;

1、状态表示

一般有三种方式可以来确定状态表示:

  • 1、题目怎么要求,我们就怎么定义状态表示
  • 2、经验 + 题目要求
  • 3、分析题目的过程中发现重复的子问题(再将重复的子问题抽象为状态表达式)

dp[i] :从 i 位置出发,到达楼顶的最小花费;

2、状态转移方程

推导状态转移方程:1、用之前或者之后的状态推导得到dp[i] 的值 2、根据最近的一步来划分问题

当我们位于 i 位置的时候,可以向前走一步到 i+1 ,也可以向前走两步到 i+2 :

从i 位置需要支付 cost[i] 的费用,有两种走法,选择费用最小的那一种就可以了;所以状态转移方程为: dp[i] = min(dp[i+1] , dp[i+2]) + cost[i];

3、初始化

初始化的目的就是为了保证在填表的时候不会发生越界访问;因为状态转移方程中会用到 dp[i+1]、dp[i+2] ,即i+1<n , i+2<n ,所以我们需要初始化 dp[n-1] 和 dp[i-2] 

  • 而从(n-1) 的位置到达楼顶就只能走一步,即花费cost[n-1] 的费用到达楼顶;
  • 而从 (n-2) 的位置到达楼顶,有两种走法,一种是走两步到楼顶,另一种是先走到(n-1) 的位置上,然后再走一步到达楼顶,即 dp[n-2] = min(cost[n-2] , cost[n-2]+dp[n-1]) ,显然cost[n-2]一定小于 cost[n-2]+dp[n-1] , 所以dp[n-2] 初始化为 cost[n-2] 就可以了;

dp[n-1] = cost[n-1] ,dp[n-2] = cost[n-2];

4、填表顺序

确定填表顺序的目的是为了保证在填表的时候,所要依据的状态已经存在了;即在填写dp[i] 的时候要保证 dp[i+1] 以及 dp[i+2] 已经填好了,故而填表顺序为从右往左;

5、返回值

根据题目要求,以及状态转移方程来确定;

因为求最初是从下标为0或者下标为1的地方开始达到楼顶的最小费用,所以应该返回这两种情况下花费的最小值;

参考代码:

    int minCostClimbingStairs(vector<int>& cost) 
    {
        int n = cost.size();
        //dp[i]:从i 位置开始,向后走到达楼顶的最小花费
        //状态转移方程: dp[i] = min(dp[i+1] , dp[i+2]) + cost[i]
        //初始化: dp[n-1] = cost[n-1] , dp[n-2] = cost[n-2];
        //填表顺序:从右往左   返回值:min(dp[0], dp[1]);
        vector<int> dp(n);
        //初始化
        dp[n-1] = cost[n-1] , dp[n-2] = cost[n-2];
        //填表
        for(int i = n-3;i>=0;i--)
        {
            dp[i] = min(dp[i+1] , dp[i+2]) + cost[i];
        }
        return min(dp[0] , dp[1]);
    }

一维线性dp:一般是由某个位置为结束或者某个位置为起点;如果以此定义状态表达式的时候能够推导出正确的状态转移方程,可以解决问题,那就说明该状态转移方程是正确的;而如果定义的这个状态表示没有办法推导出状态转移方程,没办法拿到最终的结果,那就说明该状态表示就是错的;(也就是说状态表示也会定义错,同时状态表示可以定义多个);

4、题4 解码方法:

91. 解码方法 - 力扣(LeetCode)

思考:

将 1-26 的数字转换成26 个字母;

解法:动态规划

同样地,利用动态规划来解决问题有5个步骤:

1、根据题干写出状态表示

2、推导状态转移方程

3、初始化

4、填表顺序

5、返回值

1、状态表示:

一般有三种方式可以来确定状态表示:

  • 1、题目怎么要求,我们就怎么定义状态表示
  • 2、经验 + 题目要求
  • 3、分析题目的过程中发现重复的子问题(再将重复的子问题抽象为状态表达式)

因为我们是从左往右依次解码,所以我们的dp 是一个线性的dp。这种dp 模型一般是根据经验+题目要求来定义状态的;结合本题,若以某一个位置为结尾,我们是需要解码这一串数字,那么到某一个位置为结尾的话,从左往右正好可以解码到此位置;

如上图,从 0  位置开始一直解码到 i 位置;题干求的是解码方法的总数,故而我们的状态转移方程可以定义为:从 0 到 i 位置,即以下标 i 为结尾时,所有解码方案的总数;

那么 dp[1] 表示的是前两个位置,也就是解码到下标为 1 的位置的解码方案的总数

dp[i+1] 表示:i+2 个位置,也就是解码到下标为 i+1 的位置的解码方案总数;

状态表示:dp[i]: 以 i 位置结束时,解码方法的总数

2、状态转移方程

推导状态转移方程:1、用之前或者之后的状态推导得到dp[i] 的值 2、根据最近的一步来划分问题

根据最后一步的划分来解决问题;

如若我们的状态表示是以 i 位置为结尾的解码方式的总数,那么最近的一步应该是我们正好解码至 i 位置,而解码到 i  位置又存在两种情况;第一种情况是让 i 位置单独去解码;第二种情况就是让i 位置与 (i-1) 的位置结合,然后一起去解码;

所以,我们的最后一步可以划分为:

根据划分的情况来推导我们的状态转移方程:

所以 dp[i] =  dp[s[i] 单独解码] + dp[s[i-1] 与 s[i] 结合后再解码];

3、初始化

初始化的目的就是为了让我们在填表的时候不会出现越界问题;在上述的状态转移方程中,我们会用到 dp[i-2] 、dp[i-1] 所以我们需要初始化 dp[0]、dp[1] ;

  • 以0 下标位置为结尾,只需要判断 0 下标中的数是不是0就行了,是0 则初始化为0,不是0 则初始化为1;
  • 在下标0可以单独解码得情况下,先判断 下标为1 中的字符是否可以单独进行解码,如果可以则为 dp[0] , 如果不可以则为 0; 然后需要判断下标 0 与 下标1上的两个字符是否可以结合一起解码,如果解码成功则为dp[1]+1;如果解码失败则为 0;

最后 dp[i] =  dp[s[i] 单独解码] + dp[s[i-1] 与 s[i] 结合后再解码];

本题的初始化需要根据题目来分析;

4、填表顺序

求dp[i] 的时候需要知道dp[i-1] 或者 dp[i-2] 的值,由此我们可以得知我们的填表顺序是从左往右的;

5、返回值

根据状态表示以及题干要求(求整个字符串的解码方案总数)来;

dp[i] : i 位置结束时,解码方案的总数

也就是说,我们要解码到最后一个位置,而最后一个字符的下标为 n-1 ,故而我们需要返回 dp[n-1] 

参考代码:

    int numDecodings(string s) 
    {
        int n = s.size();
        //dp[i]: 以 i 位置结束的解码方案的总数
        //状态转移方程需要分情况讨论,4种情况
        //初始化:也需要讨论  填表顺序:从左往右  返回值 :dp[n-1]
        vector<int> dp(n);
        //初始化
        dp[0] = s[0]== '0' ? 0: 1;
        //边界情况处理
        if(n==1) return dp[0];
        //先判断s[1] 是否可以单独解码
        if(s[0]!='0' && s[1]!= '0') dp[1]= 1;
        //再判断 s[0] 与 s[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];
            else dp[i] = 0;
            //再判断 i-1 与 i 结合解码是否成功
            int t = (s[i-1]-'0')*10 + (s[i]-'0');
            if(t>=10 && t<=26) dp[i]+=dp[i-2];
            else dp[i] +=0;
        }
        return dp[n-1];
    }

上面的代码中,我们的初始化也走了一边填表的逻辑,显得有点冗余,有没有什么方法可以进行优化?

  • 另一种 dp 解法,常用来处理边界情况;

可以将dp 多开辟一个空间(添加一个虚拟位置),让原来dp[1] 初始化的逻辑放在调表逻辑中;

要初始化的永远是dp 表中的前两个位置,但是新dp 通过增加一个虚拟结点,就让原本下标为1的变成了下标为2 的,也就是将原本dp[1] 的初始化逻辑合并到了填表逻辑之中;

注意事项:

1、为什么可以保证原本第二个初始化的数据放在新dp 表中的填表逻辑填时是正确的?首先保证新增的虚拟结点中的值保证后面的填表是正确的;

2、注意dp 表与原数组的下标映射关系

Q: 增加了一个虚拟结点之后,dp[0]应该初始化为什么?

  • 我们的状态转移方程: dp[i] =  dp[s[i] 单独解码] + dp[s[i-1] 与 s[i] 结合后再解码];当s[0] 可以单独解码,s[1] 可以单独解码并且 s[0] 与 s[1] 还可以结合一起解码的时候,那么dp[2] = dp[0] + dp[1]得要是2,所以dp[0] 要初始化为1;

优化参考代码:

    int numDecodings(string s) 
    {
        int n = s.size();
        //dp[i]: 以 i 位置结束的解码方案的总数
        //状态转移方程需要分情况讨论,4种情况
        //初始化:也需要讨论  填表顺序:从左往右  返回值 :dp[n-1]
        vector<int> dp(n+1);//增加一个虚拟结点
        //初始化
        dp[0] = 1;
        dp[1] = s[0]== '0' ? 0: 1;//注意下标的映射关系
        //边界情况处理
        if(n==1) return dp[1];

        //填表
        for(int i = 2;i<=n;i++)
        {
            //判断单个是否解码成功
            if(s[i-1]!='0') dp[i] = dp[i-1];//注意下标的映射关系
            else dp[i] = 0;
            //再判断 i-1 与 i 结合解码是否成功
            int t = (s[i-2]-'0')*10 + (s[i-1]-'0');//注意下标的映射关系
            if(t>=10 && t<=26) dp[i]+=dp[i-2];
            else dp[i] +=0;
        }
        return dp[n];
    }

总结

动态规划五个步骤:

  • 1、确定一个动态表达式
  • 2、根据该动态表达式来推导状态转移方程
  • 3、初始化
  • 4、填表顺序
  • 5、返回值

一般有三种方式可以来确定状态表示:

  • 1、题目怎么要求,我们就怎么定义状态表示
  • 2、经验 + 题目要求
  • 3、分析题目的过程中发现重复的子问题(再将重复的子问题抽象为状态表达式)

推导状态转移方程:1、用之前或者之后的状态推导得到dp[i] 的值 2、根据最近的一步来划分问题;

初始化的目的:保证填dp表(根据状态转移方程来调表)的时候不会发生越界;

填表顺序的目的是为了保证在填表的时候,所要依据的状态已经存在了;

vscode的launch:program ‘‘ does not exist 如图 一般是由于launch.json文件没有配置好的缘故。在右下角的ADD configuration如选第二个登录: 看到program这一栏,这一栏很重要,一般是选择你CMakelist,编译出来的可执行文件 看我CMakelist, 我生成的可执行文件是test_,所以路径可以这样输入: 我在之前cmake的时候已经有了test_这个文件了 然后就可以运... 阅读详情

相关推荐

2022年全球市场微波等离子体CVD反应器总体规模、主要生产商、主要地区、产品和应用细分研究报告

据GIR (Global Info Research)调研,按收入计,2021年全球微波等离子体CVD反应器收入大约 百万美元,预计2028年达到 百万美元,2022至2028期间,年复合增长率CAGR为 %。

MARKETRESEARCH的博客 1137

【算法与数据结构】—— 动态规划之斐波那契问题

在数学上,斐波纳契数列以如下递归方式被定义: F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N+) 根据定义,其前十项为1, 1, 2, 3, 5, 8, 13, 21, 34, 55 假设现在给出一个编程问题:输入一个自然数n,要求输出斐波那契数列的第n项(0≤n≤1000000) 如果我们根据定义来求解本题,那么...

酱懵静的博客 4136

组态王|以一定的时间间隔查询某个时间段内的历史数据

使用该函数其他都可以满足,唯一问题是变量的选择,当切换站点后查询历史数据时,所选的变量依然是上次站点查询时所选择的变量,每当更换站点查询时都需要重新选择变量,这一点太繁琐,是用户和操作者无法忍受的。但是由于现场可能数据变化并非太过频繁,想要实现记录频率不变,还是以1分钟一次的频率进行存储,但是报表查询的时候想要只显示整点的数据。其中日历控件的设置与之前的历史数据查询是一样的,报表的抬头设置都是不用变的,此处不再赘述,有兴趣的可以。以上为组态王中以一定的时间间隔查询某个时间段内的历史数据的实现过程。

做有价值的事,积累有价值的笔记! 2544

动态规划(上)---斐波那契数列

初步了解动态规划,以及通过第一个问题斐波那契数列,快速掌握动态规划的相关思想。

foreverjueye的博客 3010

【Unity】Pico VR 开发实战:从环境搭建到交互实现

本文是一份详细的Unity Pico VR开发实战指南,涵盖从环境搭建到核心交互实现的全流程。详细讲解了如何集成Pico Unity Integration SDK与XR Interaction Toolkit,配置开发环境,并重点解析了手柄输入处理、射线交互以及VR UI操作三大核心模块的代码实现与优化技巧,帮助开发者快速上手Pico VR应用开发。

rice5的博客 1175

说说PSTN、ISDN、 ADSL三种互联网接入方式的区别。

互联网的接入方式: 电话拨号接入(PSTN) ISDN接入 ADSL接入 Cable MODEM接入 局域网接入 光纤接入(FDDI) 卫星接入 DDN专线 目前来说,ADSL和Cable MODEM比较常用,今天我们就先来说说PSTN、ISDN和ADSL的区别。 电话拨号接入(PSTN/POTS,Public Switched Telephone Network / Public Oold Telephone Service) 数据终端设备(DTE)通过数据通信设备(DCE)再连

Winyaz的博客 2万+

动态规划:斐波那契数列(四种方法)

斐波那契数列 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下: F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 方法一:暴力递归 int fib(int N

qq_42847094的博客 3072

为什么PCB设计中的50Ω阻抗如此重要?从USB到以太网的实战解析

本文深入解析了PCB设计中50Ω特征阻抗的核心重要性及其工程权衡起源。文章从传输线理论出发,阐释了阻抗匹配对防止信号反射、确保信号完整性的关键作用,并对比了USB、以太网等不同应用场景的阻抗标准。同时,文章结合实际案例,剖析了在两层板等简单设计中实现精准阻抗控制的难点与实战解决方案。

weixin_29268385的博客 297

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

本文通过四道斐波那契数列模型的动态规划例题,初步了解了动态规划的一般思路

2401_86777036的博客 3024

从谱峰搜索到多项式求根:Root-MUSIC算法原理与MATLAB实践

本文深入解析Root-MUSIC算法在阵列信号处理中的原理与应用,通过多项式求根替代传统MUSIC算法的谱峰搜索,显著提升计算效率和精度。文章详细介绍了算法核心思想、MATLAB实现步骤及工程优化技巧,帮助读者掌握这一高效的DOA估计方法。

weixin_30832143的博客 80

JSON 与 JSON-RPC 的区别

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,基于文本,采用人类可读的语法来表示结构化数据。它起源于JavaScript,但如今已被几乎所有主流编程语言支持。标准文档:RFC 4627数据类型:支持 String、Number、Boolean、Null、Object、Array 六种基本类型格式示例"name": "张三","age": 30,JSON-RPC(JSON Remote Procedure Call)是一种远程过程调用(RPC)协议。

h a 6 6 6 c k 为 你解决复杂难题! 145

动态规划-斐波那契数

斐波那契数是一个很好的熟悉和理解动态规划的例子,通过斐波那契数可以更好的理解动态规划的精髓,动态规划是后面的计算是如何借助于前面的计算结果来加快计算速度的。

天使之翼 1541

Linux下的隐藏技术(文件隐藏、进程隐藏、端口隐藏、权限隐藏、命令隐藏)

这种技巧是关键记录删除,或者我们可以暴力点,比如前150行是用户的正常操作记录,150以后是攻击者操作记录。在Linux中,使用chattr命令来防止root和其他管理用户误删除和修改重要文件及目录,此权限用ls -l是查看不出来的,从而达到隐藏权限的目的。上面的命令会临时禁用历史功能,这意味着在这命令之后你执行的所有操作都不会记录到历史中,然而这个命令之前的所有东西都会原样记录在历史列表中。这种情况下我们怎么办?在shell中执行的命令,不希望被记录在命令行历史中,如何在linux中开启无痕操作模式呢?

墨痕诉清风的博客 746

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

主要介绍了动态规划中有关斐波那契数列的一类问题的解决方案

acm_pn的博客 2231

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

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

深入探讨斐波那契数列模型相关问题的解决方法,通过精心挑选的例题,每个问题都将通过状态表示、状态转移方程、初始化、填表顺序和返回值的详细分析来解构,旨在提供一个清晰的算法实现框架,帮助读者掌握DP的精髓,并在实际编程中灵活运用。​

螺蛳粉只吃炸蛋的走风的博客 1161

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

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

介绍动态规划的一些基本概念和解法流程。利用题目帮来帮助理解动态规划的斐波那契数列模型,每一步都有详细解析帮助大家熟悉动态规划的解法过程。

2301_80035594的博客 2518

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【动态规划-斐波那契数列模型】理解动态规划:斐波那契数列的递推模型

动态规划是一种解决最优化问题的强大技术,通过将问题分解为子问题并逐步求解来实现高效计算。斐波那契数列是动态规划中经典的应用之一,其递推关系非常适合用动态规划进行优化。通过动态规划,我们不仅能避免重复计算,从而大幅提高计算效率,还能直观地理解递推模型在实际问题中的应用。本文将带你深入理解斐波那契数列的递推模型,展示如何利用动态规划来优化其计算过程,并探讨这一方法的实际价值与应用。

专注于 C/C++ 后端开发,涵盖基础语法、Linux系统与网络、MySQL数据库、常见算法及项目经验。 1245

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

LeetCode相关刷题

我要学编程的博客 1056

算法沉淀 —— 动态规划篇(斐波那契数列模型)

几乎所有的动态规划问题大致可分为以下5个步骤,后续所有问题分析都将基于此1.、状态表示:通常状态表示分为以下两种,其中更是第一种为主。以i为结尾,dp[i] 表示什么,通常为代求问题(具体依题目而定)以i为开始,dp[i]表示什么,通常为代求问题(具体依题目而定)2、状态转移方程*以上述的dp[i]意义为更具, 通过最近一步来分析和划分问题,由此来得到一个有关dp[i]的状态转移方程。3、dp表创建,初始化动态规划问题中,如果直接使用状态转移方程通常会伴随着越界访问等风险,所以一般需要初始化。

Zhenyu_Coder的博客 2258

动态规划一 ——斐波那契数列模型+路径问题

dp[i][j] = min(dp[i - 1][j], min(dp[i - 1][j - 1], dp[i - 1][j + 1])) + matrix[i][j] 这个有越界情况啊。否则,万⼀ 发⽣了溢出,我们的答案就错了。不过注意一下:现在状态转移方程变成了dp[i][j]=max(dp[i-1][j],dp[i][j-1])+frame[i-1][j-1]由于我们要求的是有多少种⽅法,因此状态转移⽅程就呼之欲出了: dp[i][j] =dp[i-1][j] + dp[i][j - 1]。

2301_80224556的博客 1663

C++动态规划算法:斐波那契数列模型

本期我们将开启一个C++算法中一个重要的部分:动态规划动态规划是一个与贪心不同的问题,贪心注重于当下的每一步而达到“全局最优”,而动态规划则注重于整体的全局最优。本篇我们来介绍一下动态规划算法中一个重要的模型——斐波那契数列模型。

2401_89119815的博客 1130

动态规划(一)——斐波那契数列模型

day1动态规划入门,了解解题步骤,初步体会动态规划思想

xiaokuer_的博客 1452

动态规划入门:斐波那契数列模型以及多状态(C++)

动态规划入门:斐波那契数列模型以及多状态(C++)

2301_76269963的博客 5523

斐波那契数列模型:在动态规划的丝绸之路上追寻斐波那契的足迹(下)

上篇我们介绍了用动态规划解决斐波那契模型的相关代码,本篇我们将结合具体题目,进一步深化对于该算法的理解运用。

2303_81060385的博客 1609

斐波那契数列模型:在动态规划的丝绸之路上追寻斐波那契的足迹(上)

斐波那契数列,这一数列如同一条无形的丝线,穿越千年时光,悄然延续其魅力。在这篇文章中,我们将通过动态规划的技术来探讨如何高效地求解斐波那契数列==,从而避免传统递归方法中低效的冗余计算。我们将以 C 语言为例,展示动态规划方法如何一步步揭开这一问题的面纱。

2303_81060385的博客 3861
上一篇: C++ - 内存管理 #new/delete #operator new/operator delete #placement-new #异常
下一篇: C++ - 模板(一) #泛型编程 #函数模板 #类模板
秦少游在淮海
博客等级 码龄3年 1071粉丝 88原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值