代码随想录算法训练营第38天|动态规划理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

动态规划理论基础

文章讲解:link
视频讲解:link

  • 动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。
  • 动态规划五部曲
    • 确定dp数组(dp table)以及下标的含义(我们要用一个一维dp数组来保存“递归”的结果)
    • 确定递推公式
    • dp数组如何初始化
    • 确定遍历顺序
    • 举例推导dp数组
  • 动态规划如何debug
    • 找问题的最好方式就是把dp数组打印出来,看看究竟是不是按照自己思路推导的!
    • 做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果。
    • 如果确定思路正确,考虑是不是其他方面出了问题(初始化、遍历顺序等)

509. 斐波那契数

题目链接:link
文章讲解:link
视频讲解:link

一、做题感受&第一想法

1.递归法

class Solution {
public:
    int fib(int n) {
        if(n == 0) return 0;
        if(n == 1) return 1;
        return fib(n-1)+fib(n-2);
    }
};

二、学习文章后收获

1.递归五部曲的分析

  • 确定dp数组和下标i的含义:dp[i]就是fib(i)
  • 确定递归公式:dp[i] = dp[i-1]+dp[i-2]
  • dp数组的初始化:dp[0] = 0,dp[1] = 1
  • 确定遍历顺序:因为dp[i]靠dp[i-1]和dp[i-2]来确定,所以应该从前往后遍历( i 从小到大)。
  • 举例推导dp数组:比如如果N = 10:0 1 1 2 3 5 8 13 21 34 55

2.动态规划代码

申请一个长度为(n+1)的vector,用于记录整个dp数组

class Solution {
public:
    int fib(int n) {
        if(n <= 1) return n;
        vector<int> dp(n+1,0); //大小不是n!
        dp[1] = 1;
        for(int i = 2;i <= n;i++){
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
};

3.优化后的代码

不需要长度为n+1的vector数组,只需要2个变量即可

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

70. 爬楼梯

题目链接:link
文章讲解:link
视频讲解:link

一、做题感受&第一想法

  • 动态规划五部曲:
    • 确定dp[i]和i含义:dp[i]:爬到第i层台阶时可用的方法总数
    • 递推公式:dp[i] = dp[i-1] + dp[i-2]
    • dp初始值:dp[1] = 1,dp[2] = 2
    • 遍历顺序:从前往后
    • 序列:1,2,3,5,8,……(其实就是斐波那契数列!唯一的区别是,没有讨论dp[0]应该是什么,因为dp[0]在本题没有意义!)
class Solution {
public:
    int climbStairs(int n) {
        //dp[i]:爬到第i层台阶时可用的方法总数
        //递推:dp[i] = dp[i-1] + dp[i-2];
        if(n <= 2) return n;
        int dp1 =  1, dp2 = 2, cur = 0;
        for(int i = 3;i <= n;i++){ //要求dp[n],所以i可以取到n
            cur = dp1 + dp2;
            dp1 = dp2;
            dp2 = cur;
        }
        return cur;
    }
};

二、学习文章后收获

1.拓展问题:

#include<iostream>
#include<vector>
using namespace std;

int main(){
    int m = 0,n = 0;
    scanf("%d %d",&n,&m);
    
    vector<int> dp(n+1,0); 
    dp[1] = 1;
    
    //初始化前m个dp元素
    for(int i = 2;i <= m;i++){
        for(int j = 1;j < i;j++){
            dp[i] += dp[j]; //把前面所有元素的方法数都加起来
        }
        dp[i]++; //注意点:加上从第一层直接跳到第i层的“1”种方法!!!
    }
    
    for(int i = m + 1;i <= n;i++){
        for(int j = 1;j <= m;j++){
            dp[i] += dp[i - j]; //把前面m个元素的方法数都加起来
        }
    }
    
    cout << dp[n] <<endl;
    return 0;
}

三、过程中遇到的问题

1.编译器选错导致的报错

Main.c:1:9: fatal error: iostream: No such file or directory
1 | #include
| ^~~~~~~~~~
compilation terminated.
错误原因:我把编译环境选成C了,然而我写的C++程序。。。


746. 使用最小花费爬楼梯

题目链接:link
文章讲解:link
视频讲解:link

一、做题感受&第一想法

  • 动态规划五要素:
    • dp和i的含义:dp[i]表示到第i个台阶时,最小花费
    • 递推公式:dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])
    • dp初始化:dp[0] = 0, dp[1] = 0;
    • 遍历顺序:从前到后
    • 手算序列:(略,没法写,不知道cost[]。)
class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        int n = cost.size();
        vector<int> dp(n + 1,0); //到第i个台阶的最小花费。最后一个元素dp[n],到楼顶
        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];
    }
};
  • 19
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值