算法刷题打卡039 | 动态规划7

LeetCode 70 爬楼梯(进阶)

题目链接:70. 爬楼梯 - 力扣(Leetcode)

爬楼梯原题是每次爬一阶或者两阶的楼梯,属于简单的斐波那契数列应用。当每次可以爬的阶数扩展到1到m(也就是每跨一步可以选择跨1个台阶、2个台阶、...、m个台阶),状态推导从只考虑前两个状态变为考虑前m个状态,用同样的动态规划也能做,通过m控制第二个for循环的遍历范围:

class Solution {
public:
    int climbStairs(int n) {
        if (n<=2) return n;
        vector dp(n+1, 0);
        dp[1] = 1;
        dp[2] = 2;
        int m = 2;
        for(int i=3; i<=n; i++){
            for (int j=i-1; j>=i-m; j--){
                if (j >= 0) dp[i] += dp[j];
                else break;
            }
        }
        return dp[n];
    }
};

运用完全背包理论解题,每次可以跨的台阶数1-m就是物品,每次跨的台阶数可以重复,一共要爬的n阶就是背包容量,最终要求的是装满背包的方法种数,并且要考虑不同的爬楼梯次序,因此属于排列问题,物品应该在内层循环遍历。

但其实具体实现的时候和常规动态规划的代码基本一样,外层for循环就是背包容量,内层for循环就是物品。不同的是背包容量从0开始,需要将dp[0]初始化为1,才能顺利推导后面的状态,但实际上dp[0]没有实际意义:

class Solution {
public:
    int climbStairs(int n) {
        if (n<=2) return n;
        vector dp(n+1, 0);
        dp[0] = 1;
        int m = 2;
        for(int i=1; i<=n; i++){
            for (int j=1; j<=m; j++){
                if (i - j >= 0) dp[i] += dp[i - j];
                else break;
            }
        }
        return dp[n];
    }
};

为了体现求“排列”种数,将内层for循环的index修改为正序的1到m。

LeetCode 322 零钱兑换

题目链接:322. 零钱兑换 - 力扣(Leetcode)

零钱兑换也是一看就是完全背包,但问题的解要求是装满背包的最少物品数,这和是排列还是组合问题关系不大,因此物品和背包容量的遍历顺序。dp状态从可以放下当前coins[i]的硬币数+1更新,因为要取最小值,dp数组除了dp[0],都要初始化为INT_MAX,dp[0]所需的最小硬币数为0。同时还要注意遍历更新状态时,如果前一个状态没有被更新,INT_MAX加1会导致整型溢出,因此需要增加一个if条件判断,返回值也要判断是否有被更新,无法凑成目标的amount时dp[amount]仍旧为INT_MAX,而题目要求的返回值是-1。

class Solution {
public:
    int coinChange(vector& coins, int amount) {
        int n = coins.size();
        vector dp(amount+1, INT_MAX);
        dp[0] = 0;
        for (int i=0; i

LeetCode 279 完全平方数

题目链接:279. 完全平方数 - 力扣(Leetcode)

凑完全平方数的过程和零钱兑换异曲同工,但完全平方数可以用不限量的1去凑,总是可以凑出一种结果,返回值不需要判断dp[n]是否被更新:

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

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