代码随想录算法训练营Day28 | 509.斐波那契数列、70.爬楼梯、746.使用最小花费爬楼梯

LeetCode509.斐波那契数列

509. 斐波那契数 - 力扣(LeetCode)

1.思路

动态规划

斐波那契数列这道题算是最简单的动态规划的题了。接下来通过这道题来掌握

动态规划五部曲:

1.确定dp数组及下标的含义:dpi -> 第i个斐波那契数的值;

2.确定递推公式:状态转移方程 -> dpi = dpi - 1 + dpi - 2 ;

3.dp数组如何初始化:dp0=0,dp1=1;

4.确定遍历顺序:从状态转移方程可知 dpi 依赖于 dpi-1 和 dpi-2,所以遍历顺序一定是从前向后的;

5.举例推导dp数组:

当N为10的时候,dp数组应该是这样的数列: 0 1 1 2 3 5 8 13 21 34 55 ,如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的。

cpp 复制代码
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];
    }
};
优化

这里其实只需要维护两个数值,所以不需要记录整个序列,就只需要定义两个变量并记录最后的值即可。

cpp 复制代码
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];
    }
};
递归

递归的方法是最常见的。

cpp 复制代码
class Solution {
public:
    int fib(int n) {
        if(n<=1) return n;
        return fib(n-1)+fib(n-2);
    }
};

2.复杂度分析

时间复杂度:O(n) - 动规、优化,O(2^n) - 递归

空间复杂度:O(n) - 动规、递归,O(1) - 优化

3.思考

这道题虽然很简单,但确是掌握动态规划的入门第一步,我们要从中熟悉并掌握动态规划题目的解题方法思想。

4.Reference:509. 斐波那契数 | 代码随想录


LeetCode70.爬楼梯

70. 爬楼梯 - 力扣(LeetCode)

1.思路

这道题需要多举几个例子,例如爬到第一层楼梯有一种方法,爬到第二层有两种方法,爬到第三次有三种方法,依次类推。可以得知,爬到第三层的方法由爬到第二层和爬到第一层的方法推导出来。

动态规划五部曲:

  1. dpi:爬到第 i 层楼梯有 dpi 种方法;

  2. 要到达 dpi ,可以从 dpi-1 处跳一步,也可以从 dpi-2 处跳两步,由此可知,dpi = dpi-1 + dpi-2

  3. 爬到第一层有 1 种方法,爬到第二层有 2 种方法,所以 dp1 = 1,dp2 = 2 。这里不需要从 0 开始初始化,因为爬到第 0 层的方法为 0 ,而且 dpi 表示的是爬到第 i 层的方法数,如果从 0 开始初始化的话意义就不是那么明显,并且题目说了 n 是一个正整数,所以从 0 开始初始化压根就没意义;

  4. 由递归公式可知,dpi 依赖于 dpi-1、dpi-2,所以从前往后遍历;

  5. 依旧举例比较,当 n 为 5 的时候,dp数组应该是这样的数列:1 2 3 5 8 ;

cpp 复制代码
// 版本一
class Solution {
public:
    int climbStairs(int n) {
        if (n <= 1) return n; 
        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];
    }
};
cpp 复制代码
// 版本二
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];
    }
};

2.复杂度分析

时间复杂度:O(n)

空间复杂度:O(n) - 方法一,O(1) - 方法二

3.思考

这道题和斐波那契数列那道题的递推公式是一样的,但是如果是第一次做还是有难度的,因为这里的递推公式得自己去推,dp数组的初始化也得思考一下是否有意义。

4.Reference:70. 爬楼梯 | 代码随想录


LeetCode746.使用最小花费爬楼梯

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

1.思路

题目说的可以自行选择下标 0 或下标 1 的台阶开始爬楼梯,也就相当于跳到下标 0 或 1 是不消耗体力的。

动态规划五部曲:

  1. dpi:到达第 i 个台阶所需要的最小体力;

  2. dpi 可由 dpi-1 跳到 dpi,此时花费 dpi-1+costi-1;也可以由 dpi-2 跳到 dpi,此时花费 dpi-2 + costi-2,由于 dpi 是到第 i 个台阶的最小体力,所以 dpi = min(dpi-1+costi-1,dpi-2+costi-2) ;

  3. 由题目可知,跳到下标 0 或下标 1 是不消化体力的,所以可以初始化 dp0=0,dp1=0;

  4. 由递推公式可知是从前往后遍历的;

  5. 拿示例2:cost = 1, 100, 1, 1, 1, 100, 1, 1, 100, 1 ,dp = 0,0,1,2,2,3,3,4,4,5,6

cpp 复制代码
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()];
    }
};

优化

cpp 复制代码
class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        int dp0=0;
        int dp1=0;
        for(int i=2;i<=cost.size();i++){
            int sum=min(dp0+cost[i-2],dp1+cost[i-1]);
            dp0=dp1;
            dp1=sum;
        }
        return dp1;
    }
};

2.复杂度分析

时间复杂度:O(n)

空间复杂度:O(n),O(1) - 优化

3.思考

这道题较前两到题就上难度了,因为不是单纯的由前两个 dp 数组的状态相加得到的,这里还需要加上从当前位置起跳的花费 costi,最终还要存最小值,所以状态转移方程就很难想到;其次是 dp 数组的初始化,这里必须要读懂题目,可以任意选择从 0 或 1 位置开始走,就说明跳到 0 或 1 是不消耗体力的。

4.Reference:746. 使用最小花费爬楼梯 | 代码随想录

相关推荐
8Qi84 小时前
回文子串(Palindromic Substrings)—— 题解
算法·leetcode·职场和发展·动态规划
小宋加油啊8 小时前
机械臂抓取物体 PVN3D算法调研学习
学习·算法·3d
lqqjuly8 小时前
前沿算法深度解析(一)
算法
小欣加油9 小时前
leetcode1926 迷宫中离入口最近的出口
数据结构·c++·算法·leetcode·职场和发展
happymaker062611 小时前
LeetCodeHot100——42.接雨水
算法
阿正的梦工坊12 小时前
【Rust】07-错误处理:Option、Result 与 ? 运算符
开发语言·算法·rust
八解毒剂13 小时前
数据结构-平衡二叉树——对二叉搜索树的优化
数据结构·c++·算法
运行时记录13 小时前
别再手动写提示词了 — SkillOpt 让技能文档自己进化
算法
啦啦啦啦啦zzzz14 小时前
算法总结(二分查找、双指针)
c++·算法