代码随想录算法训练营第四十五天|70. 爬楼梯(进阶版)、322. 零钱兑换、279.完全平方数

70. 爬楼梯(进阶版)

此题一开始学习动态规划的时候就做过,用的类斐波那契的递推公式,本题如果升级难度,将一次只能跨一步或者两步台阶,扩展到一次可以一步、两步、三步……m步,就不能那样做了,可以转化为完全背包的问题。【1-m】是物品的重量和价值,跨到多少节是背包

  1. dp数组及下标含义
    dp[i]:爬到有i个台阶的楼顶,有dp[i]种方法

  2. 递推公式
    dp[i]有几种来源,dp[i - 1],dp[i - 2],dp[i - 3] 等等,即:dp[i - j]

    那么递推公式为:dp[i] += dp[i - j]

  3. 初始化
    既然递归公式是 dp[i] += dp[i - j],那么dp[0] 一定为1,dp[0]是递归中一切数值的基础所在,如果 dp[0]是0的话,其他数值都是0了。

    下标非0的dp[i]初始化为0,因为dp[i]是靠dp[i-j]累计上来的,dp[i]本身为0这样才不会影响结果

  4. 确定遍历顺序
    这是背包里求排列问题,即:1、2 步 和 2、1 步都是上三个台阶,但是这两种方法不一样!

    所以需将target放在外循环,将nums放在内循环。

    每一步可以走多次,这是完全背包,内循环需要从前向后遍历

class Solution {
public:
    int climbStairs(int n) {
        vector<int> dp(n + 1, 0);
        dp[0] = 1;
        for (int i = 1; i <= n; i++) { // 遍历背包
            for (int j = 1; j <= m; j++) { // 遍历物品, m换成2就是前面的基础问题
                if (i - j >= 0) dp[i] += dp[i - j];
            }
        }
        return dp[n];
    }
};

322. 零钱兑换

  1. 确定dp数组以及下标的含义
    dp[j]:凑足总额为j所需钱币的最少个数为dp[j]

  2. 确定递推公式
    凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i])

    所以dp[j] 要取所有 dp[j - coins[i]] + 1 中最小的。

    递推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);

  3. dp数组初始化
    首先凑足总金额为0所需钱币的个数一定是0,那么dp[0] = 0;

    考虑到递推公式的特性,dp[j]必须初始化为一个最大的数,否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。

    所以下标非0的元素都是应该是最大值。

  4. 确定遍历顺序
    本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数。

    那么采用coins放在外循环,target在内循环的方式。

    本题钱币数量可以无限使用,那么是完全背包。所以遍历的内循环是正序

    综上所述,遍历顺序为:coins(物品)放在外循环,target(背包)在内循环。且内循环正序。

  5. 举例
    以输入:coins = [1, 2, 5], amount = 5为例
    代码随想录算法训练营第四十五天|70. 爬楼梯(进阶版)、322. 零钱兑换、279.完全平方数_第1张图片

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(amount + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 0; i < coins.size(); i++) {
            for (int j = coins[i]; j <= amount; j++) {
                if (dp[j - coins[i]] != INT_MAX) { // 如果dp[j - coins[i]]是初始值则跳过
                    dp[j] = min(dp[j - coins[i]] + 1, dp[j]);
                }
            }
        }
        return dp[amount] == INT_MAX ? -1 : dp[amount];
    }
};

279.完全平方数

此题和上题类似

class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 1; i * i <= n; i++) {
            for (int j = i * i; j <= n; j++) {
                dp[j] = min(dp[j - i * i] + 1, dp[j]);
            }
        }
        return dp[n];
    }
};

你可能感兴趣的:(leetcode刷题打卡,算法,动态规划,leetcode)