代码随想录第三十八天——斐波拉契数列,爬楼梯,使用最小花费爬楼梯

news/2024/7/5 20:02:06 标签: 算法, leetcode, 数据结构, 动态规划

动态规划基础

动态规划中每一个状态一定是由上一个状态推导出来的
动态规划的解题步骤可以拆解为如下五步:

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

leetcode_509__8">leetcode 509. 斐波拉契数列

题目链接:斐波拉契数列

class Solution {
public:
    int fib(int N) {
        if (N <= 1) return N;
        vector<int> dp(N + 1);
        dp[0] = 0;  //初始化
        dp[1] = 1;
        for (int i = 2; i <= N; i++)   //遍历顺序:从前到后
        {
            dp[i] = dp[i - 1] + dp[i - 2];  //递推公式
        }
        return dp[N];
    }
};

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

为了减小空间复杂度,可以只维护两个数值就可以了,不需要记录整个序列:

class Solution {
public:
    int fib(int N) {
        if (N <= 1) return N;
        int dp[2];  
        dp[0] = 0;
        dp[1] = 1;
        for (int i = 2; i <= N; i++) {
            int sum = dp[0] + dp[1];
            dp[0] = dp[1];
            dp[1] = sum;
        }
        return dp[1];
    }
};

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

leetcode_70__50">leetcode 70. 爬楼梯

题目链接:爬楼梯
爬到第一层楼梯有一种方法,爬到二层楼梯有两种方法。
那么第一层楼梯再跨两步就到第三层 ,第二层楼梯再跨一步就到第三层。所以到第三层楼梯的状态可以由第二层楼梯和到第一层楼梯状态推导出来,那么就可以使用动态规划了。

  1. 确定dp数组以及下标的含义
    dp[i]: 爬到第i层楼梯,有dp[i]种方法
  2. 确定递推公式
    dp[i] 可以有两个方向推出来:
    一是dp[i - 1],上i-1层楼梯,有dp[i - 1]种方法,那么再一步跳一个台阶就是dp[i]了。
    二是dp[i - 2],上i-2层楼梯,有dp[i - 2]种方法,那么再一步跳两个台阶就是dp[i]了。
    所以dp[i] = dp[i - 1] + dp[i - 2]
  3. dp数组初始化
    dp[1] = 1dp[2] = 2dp[0]在本题没有意义。
  4. 确定遍历顺序
    从前向后遍历
  5. 举例推导
    n = 5时,dp数组为1,2,3,5,8,和斐波拉契数列是一致的

版本一:

class Solution {
public:
    int climbStairs(int n) {
        if (n <= 1) return n; // 因为下面直接对dp[2]操作了,防止空指针
        vector<int> dp(n + 1);
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) { // 注意i是从3开始的
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
};

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

版本二:

class Solution {
public:
    int climbStairs(int n) {
        if (n <= 1) return n;
        int dp[3];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            int sum = dp[1] + dp[2];
            dp[1] = dp[2];
            dp[2] = sum;
        }
        return dp[2];
    }
};

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

leetcode_746__106">leetcode 746. 使用最小花费爬楼梯

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

  1. 确定dp数组以及下标的含义
    dp[i]的定义:到达第i台阶所花费的最少体力为dp[i]
  2. 确定递推公式
    dp[i - 1] 跳到 dp[i] 需要花费 dp[i - 1] + cost[i - 1]
    dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]
    dp[i]选最小的,所以dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2])
  3. dp数组初始化
    题目中 “你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。” 说明到达第0个台阶是不花费的,从第0个台阶往上跳需要花费 cost[0]。
    所以dp[0] = 0dp[1] = 0
  4. 遍历顺序
    从前到后遍历cost数组
  5. 举例推导dp数组

版本一:

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()];
    }
};

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

版本二:

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        int dp0 = 0;
        int dp1 = 0;
        for (int i = 2; i <= cost.size(); i++) {
            int dpi = min(dp1 + cost[i - 1], dp0 + cost[i - 2]);
            dp0 = dp1; // 记录一下前两位
            dp1 = dpi;
        }
        return dp1;
    }
};

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


http://www.niftyadmin.cn/n/5301670.html

相关文章

MySQL基础学习: 第一章 数据库概述

一、数据库介绍 数据库就是存储、维护和管理数据的仓库。数据库管理系统DBMS就是用来操作维护和管理数据库的大型软件。 ​​​​​​​​ 二、数据库的分类 1、关系型数据库 Oracle&#xff1a;收费MySQL&#xff1a;免费SQLSERVER&#xff1a;收费hiveTIDB人大金仓&#…

阿里云免费SSL证书有效期3个月有什么解决方法?

阿里云免费SSL证书签发有效期从12个月缩短至3个月&#xff1a;尊敬的用户&#xff0c;根据供应商变更要求&#xff0c;免费证书&#xff08;默认证书&#xff09;的签发有效期将由12个月缩短至3个月。 免费证书&#xff08;升级证书&#xff09;的有效期不会改变。 没错&#…

三菱plc的点动控制循环(小灯闪烁,单控气缸循环)

以为前一段时间小编做了一个气缸定时循环的程序&#xff0c;根据程序有不足之处&#xff0c;所以小编写下这篇文章&#xff0c;将网络上的plc小灯控制进行总结&#xff01;如果对你有帮助&#xff0c;不要忘了点赞收藏&#xff01;如果有更加好的梯形图&#xff0c;欢迎评论&am…

哪些算法可以用于文字识别?

文字识别是计算机视觉领域的一个重要应用&#xff0c;它是指利用计算机技术将图像中的文字转换成可编辑的文本格式的过程。在实现文字识别时&#xff0c;可以使用不同的算法和技术&#xff0c;以下是一些常用的算法和技术&#xff1a; 1.光学字符识别&#xff08;OCR&#xff…

正则表达式 详解,10分钟学会

大家好&#xff0c;欢迎来到停止重构的频道。 本期我们讨论正则表达式。 正则表达式是一种用于匹配和操作文本的工具&#xff0c;常用于文本查找、文本替换、校验文本格式等场景。 正则表达式不仅是写代码时才会使用&#xff0c;在平常使用的很多文本编辑软件&#xff0c;都…

CISSP 第1章:实现安全治理的原则和策略

作者&#xff1a;nothinghappend 链接&#xff1a;https://zhuanlan.zhihu.com/p/669881930 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 CIA CIA 三性&#xff1a; 机密性&#xff1a;和数据泄露有关。完整性…

Javascript 正则表达式零宽断言

在介绍正则表达式零宽断言这个概念之前&#xff0c;先看一下以下这道有关 javascript 正则表达式的题目&#xff1a; 登录注册流程是前端最常见的业务流程之一&#xff0c;注册流程少不了密码强弱度校验&#xff0c;请实现对密码的校验&#xff0c;要求满足&#xff1a; 包含大…

CUMT--Java复习--核心类

目录 一、装箱与拆箱 二、“”与equals 三、字符串类 1、String、StringBuffer、StringBuilder的区别 2、String类 3、StringBuffer类 4、StringBuilder类 四、类与类之间关系 一、装箱与拆箱 基本类型与对应封装类之间能够自动进行转换&#xff0c;本质就是Java的自…