【算法训练记录——Day38】

1.理论

一般解题步骤:

  1. 确定dp数组及下标含义
  2. 确定递推公式
  3. 数组如何初始化
  4. 确定递归顺序
  5. 举例推导dp数组

#2.leetcode_509斐波那契数

在这里插入图片描述
思路:1. 递归
2. 动态规划的方式考虑5个问题:
1. dp数组及下标的含义: 第i个数的斐波那契数值是dp[i]
2. 递推公式:f[i] = f[i-1] + f[i-2];
3. 数组如何初始化:因为递推公式用到了i-1 i-2,因此初始化0,1位置
4. 确定递归顺序:
5. 举例推导递推公式 dp[i] = dp[i-1] + dp[i-2];

	int fib(int n) {
        if(n < 2) return n;
        vector<int> dp(n+1); // 第n个数的斐波那契数列值是dp[n],因此最少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];
    }

优化下:

	int fib(int n) {
        if(n < 2) return n;
        int dp[2] = {0};
        dp[0] = 0;
        dp[1] = 1;

        for(int i = 2; i <= n; i++) {
            dp[1] = dp[1] + dp[0];
            dp[0] = dp[1] - dp[0];
        }

        return dp[1];
    }

3.leetcode_70爬楼梯

在这里插入图片描述
思路:熟悉一下动态规划5步:
1. 确定动态规划数组及下标含义:爬 i 阶的楼梯共有 dp[i] 种爬法, i > 0
2. 确定递推公式: f(i) = f(i-2) + 2; 每次可以爬1~2个,这里每次只有两种爬法,1+1 / 2
3. 数组如何初始化:至少需要知道 i-2 > 0 的爬法有多少种, 初始化 dp[0], dp[1];
4. 确定递推顺序:从前向后
5. 举例推导 dp 数组: dp[i] = dp[i-2] + 2; (i >= 2)
写了一下,答案错误,感觉模拟的没问题,应该是递推公式有误,虽然只有两种爬法,但没有考虑如果是3,既可以先爬一步再爬两步,也可以先爬两步再爬一步。。确定递推公式时,如果爬两个一步,那不就是 i - 1的爬法吗,如果爬两步那就是i - 2的爬法,所以应该是 f(i) = f(i-1) + f(i-2);

	int climbStairs(int n) {
        int dp[2];
        dp[0] = 1;
        dp[1] = 1;
        for(int i = 2; i <= n; i++) {
            dp[1] += dp[0];
            dp[0] = dp[1] - dp[0];
        }
        return dp[1];
    }

4.kamacoder_57爬楼梯

在这里插入图片描述
思路:

  1. 确定动态规划数组及下标含义:爬 n 阶楼梯共有 dp[n] 种方法
  2. 确定递推公式:f(n) = f(n-1) + f(n-2) + … + f(n-m)
  3. 数组如何初始化: dp[0] = 1
  4. 确定顺序:从前向后
  5. 举例推导 dp 数组: dp[i] = dp[i-1] + … + dp[i-m];
	#include <iostream>
#include <vector>

using namespace std;

int main(){
    int n, m;
    cin >> n >> m;
    
    vector<int> dp(n + 1, 0);
    
    dp[0] = 1;
    
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            // cout << i << " " << j << " ";
            if(i >= j) {
                dp[i] += dp[i-j];
                // cout << dp[i] << " " << dp[i-j];
            }
            // cout << endl;
        }
    }
    cout << dp[n];
    return 0;
}

5.leetcode_746使用最小花费爬楼梯

在这里插入图片描述
思路:

  1. 确定动态规划数组及下标含义:从 n 阶楼梯爬到顶最少花费 dp[n]
  2. 确定递推公式:f(n) = min(f(n-1),f(n-2));
  3. 数组如何初始化: dp[n] = cost[n], dp[n-1] = cost[n-1];
  4. 确定顺序:从后向前,从已知到未知
  5. 举例推导 dp 数组: dp[n] = min(dp[n+1], dp[n+2]) + cost[n];
	int minCostClimbingStairs(vector<int>& cost) {
        int dp[2];
        int size = cost.size();

        dp[1] = cost[size - 1];
        dp[0] = cost[size - 2];

        for(int i = size - 3; i >= 0; i--) {
            int tmp = dp[0];
            dp[0] = min(tmp, dp[1]) + cost[i];
            dp[1] = tmp;
        }
        return min(dp[0], dp[1]);
    }

题解方法二:

	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;
    }
  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值