LeetCode题解 动态规划(一):509 斐波那契数;70 爬楼梯;746 使用最小花费爬楼梯

动态规划

基础

动态规划,又名状态转移过程的求解,本质上是由一个状态达到另一个状态时,值的变化,最终影响所求解问题。

强化学习最初的算法中,就有动态规划。

随想录中则是提出了动态规划的五个步骤,我认为可以分为上半部分和下半部分:

上半部分——理论

1 - 确定dp数组的含义:即我们求解的问题是什么

2 - 确定递推公式:当前状态如何由之前的状态推导而来

下班部分——实操

3 - dp数组如何初始化:既然其他状态都由状态推导而来,那么必然就会有个初始状态,往往先确定递推公式,反过来确定初始状态会更容易一些

4 - 确定遍历顺序:这一点往往比较难想,涉及到不同的问题

5 - 举例推导dp数组:这一步是为了验证前面四步是否是正确的

509 斐波那契数 easy

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n) 。

这道题,没什么可说的,因为递推公式和初始状态都已经给出来了,照着写题就行,因为求的是最终结果,那么直接用O(1)的空间复杂度来解决就可以了,代码如下:

int fib(int n) {
    
    
    if (n <= 1) return n;
    int res;
    int dp1 = 0;
    int dp2 = 1;

    for (int i = 2; i <= n; i++) {
    
    
        res = dp1 + dp2;
        dp1 = dp2;
        dp2 = res;
    }

    return res;
}

70 爬楼梯 easy

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

这道题就可以稍微用用上面提到的五部曲了“

1 - dp[i] 表示爬到第i阶时一共可以有的方法

2 - dp[i] = dp[i - 1] + dp[i - 2],即爬到现在这个台阶可以用的方法,是从下一级和下两级方法的总和

3 - 如果台阶只有一阶,那么方法就只有一种

4 - 楼梯要从下往上走,那么遍历顺序从前往后,就是毋庸置疑的

5 - 举例:以台阶有两级为例,

有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶

代码如下:

int climbStairs(int n) {
    
    
    vector<int> dp(n + 1, 0);
    if (n <= 1) return 1;
    dp[0] = 1, dp[1] = 1;

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

如果要优化一下空间复杂度,可以考虑不用数组,而是直接使用三个变量表示状态之间的关系就可以了。此处省略。


746 使用最小花费爬楼梯 easy

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

还是五部曲:

1 - 确定dp数组的含义:毋庸置疑,就是爬到第i个台阶时,花费的总费用

2 - 推导dp公式:爬到当前台阶,有两种前置状态:从上一个台阶走了一步,从上两个台阶走了两步,别无其他。那么dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i],由于之前的状态必然是要往上走的,所以还要加上当前台阶所需的费用。

3 - 确定初始值:台阶0 和 台阶1都是该台阶往上走的花费

4 - 确定遍历顺序:从前往后(毕竟这是简单题的水平

5 - 举例:省略

这道题的代码我们就用省空间的写法来解,代码如下:

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

猜你喜欢

转载自blog.csdn.net/qq_41205665/article/details/128908092
今日推荐