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

LeetCode 70. 爬楼梯(进阶)

链接:70. 爬楼梯(进阶)

思路:

本题之前也用dp做过,这里用了完全背包的思路,物品就是1和2,表示一次可以爬一层或者两层,背包大小就是楼梯,所求的就是用物品(爬一层或者两层)正好装满背包(爬到顶层)的所有排列方式。因为物品可以重复选取,所以是完全背包,题目查找排列方式,所以先遍历背包再遍历物品,递推公式dp[j] += dp[j-i]。

代码:

class Solution {
public:
    int climbStairs(int n) {
        vector dp(n+1);
        dp[0] = 1;
        // 完全背包,先遍历背包再遍历物品
        for (int j = 0; j <= n; j++)
            for (int i = 1; i <= 2; i++)
                if (j >= i)
                    dp[j] += dp[j-i];
        return dp[n];
    }
};

LeetCode 322. 零钱兑换

链接:322. 零钱兑换

思路:

这道题的思路稍有不同,但本质上还是一个完全背包的问题。首先定义下标,dp[i]表示组成总金额i的所需最少硬币个数。然后初始化dp,因为题目要求找的是最少硬币个数,在递推公式的时候一定会有一个取最小的操作,如果dp初始化为0,不管计算结果如何取最小后都是0,所以dp应该初始化为最大值INT_MAX,这里初始化为INT_MAX - 1是为了防止后面+1的时候溢出。dp[0]应该初始化为0,因为组成总金额0所需要的硬币数为0。

接下来是递推公式,dp[j]表示不选coins[i]时组成金额j所需的最小硬币数,dp[j-coins[i]]+1表示选取coins[i]时,所需最小硬币数为j-coins[i]]所需的最小硬币数加1,然后我们需要在两者之间选一个最小值,所以dp[j] = min(dp[j], dp[j-coins[i]] + 1)。然后是确认遍历顺序,这里我们不考虑到底是组合还是排列,而只需要考虑是否能够凑出所需要的数目,所以不管是先遍历背包还是先遍历物品都是可以的。

最后要考虑不能凑成所需要的总额的情况,如果不能凑成,dp应该为初始化的值,所以当dp[amout]为初始的值的时候,返回-1,否则返回dp[amount]。

代码:

class Solution {
public:
    int coinChange(vector& coins, int amount) {
        // 定义下标:dp[i]表示组成总金额i的所需最少硬币个数
        vector dp(amount + 1, INT_MAX - 1);
        dp[0] = 0;
        // 完全背包,先遍历物品后遍历背包
        for (int i = 0; i < coins.size(); i++)
        {
            for (int j = coins[i]; j <= amount; j++ )
                dp[j] = min(dp[j], dp[j-coins[i]] + 1);
        }

        if (dp[amount] == INT_MAX - 1)
            return -1;
        else
            return dp[amount];
    }
};

LeetCode 279.完全平方数

链接:279.完全平方数

思路:

这道题目和上面一题类似,都是找组成目标数的最少数量,所以初始化dp为INT_MAX -1,减一是为了防止溢出。然后根据定义初始化dp[0]和dp[1],dp[0]初始化为0,其实在这里初始化为0是没有数学意义的,只是为了方便递归,dp[1]初始化为1,因为和为1所需要的最少数量为1。

然后是确认递推公式,和上一题类似,只不过物品变成了完全平方数,只需要从开始遍历小于n的完全平方数即可。i*i保证了它们的乘积一定是完全平方数,所以递推公式为dp[j] = min(dp[j], dp[j - i * i] + 1)。同样,这题的遍历顺序也可以先遍历背包或者先遍历物品。

代码:

class Solution {
public:
    int numSquares(int n) {
        // 定义下标:dp[i]表示和为i的完全平方数的最少数量
        vector dp(n + 1, INT_MAX - 1);
        // 初始化dp,和为0所需要的最少数量为0,和为1所需要的最少数量为1
        dp[0] = 0;
        dp[1] = 1;
        // 先遍历物品再遍历背包
        for (int i = 1; i * i <= n; i++)
        {
            for (int j = i * i; j <= n; j++)
                    dp[j] = min(dp[j], dp[j - i * i] + 1);
        }
        return dp[n];
    }
};

你可能感兴趣的:(代码随想录算法训练营,算法,leetcode,动态规划)