算法学习day45

算法学习day45

  • 1.力扣 70. 爬楼梯 (进阶)
    • 1.1 分析
    • 1.2 代码
  • 2. 力扣 322. 零钱兑换
    • 2.1 分析
    • 2.2 代码
  • 3. 力扣279.完全平方数
    • 3.1 分析
    • 3.2 代码
  • 4.参考资料

1.力扣 70. 爬楼梯 (进阶)

1.1 分析

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数组如何初始化

由递推公式:dp[i] += dp[i - j]得出dp[0] = 1,如果为0无法推了,全部都是0.

4.确定遍历顺序

1步、2步和2步、1步都是上三个台阶,但是是两种方法。

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

5.举例推导dp数组

算法学习day45_第1张图片

1.2 代码

class Solution {
public:
    int climbStairs(int n) {
        vector<int> dp(n + 1, 0);                    // 初始化动态规划数组
        dp[0] = 1;                                   // 边界条件,当 n = 0 时有一种爬楼梯的方法
        for(int i = 1 ; i <= n ; i++){               // 遍历台阶数,从1到n
            for(int j = 1 ; j <= 2 ; j++){           // 遍历可以选择的步数,1或2
                if( i - j >= 0) dp[i] += dp[i - j];  // 状态转移方程,由 dp[i-j] 转移得到 dp[i]
            }
        }
        return dp[n];                                // 返回爬到第n个台阶的方案数
    }
};

2. 力扣 322. 零钱兑换

2.1 分析

1.确定dp数组以及下标的含义

dp[j] : 凑满总额为j需要钱币的最小个数为dp[j]

2.确定递推公式

凑总额为j - coins[i] 的最小个数为dp[ j - coins[i]] , 加上减去的钱币的个数 dp[j -coins[i]] + 1 就是dp[j]

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

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

3.dp数组如何初始化

由递推公式可知,由于是求最小值dp[j]必须初始化为一个最大的数,否则在min中被初始值覆盖。

vector<int> dp(amount + 1 , INI_MAX);
dp[0] = 0;

4.确定遍历顺序

如果求组合数外层for循环物品,内层for循环背包。

如果求排列数外层for循环背包,内层for循环物品。

5.举例推导dp数组
算法学习day45_第2张图片

2.2 代码

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        // 初始化dp数组,将0元的硬币兑换方法设置为0,其他的为INT_MAX
        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++) {
                // 如果dp[j - coins[i]]是初始值则跳过,否则更新dp[j]
                if (dp[j - coins[i]] != INT_MAX) {
                    dp[j] = min(dp[j - coins[i]] + 1, dp[j]);
                }
            }
        }
        // 如果dp[amount]仍为初始值,说明无法使用硬币兑换成目标金额
        if (dp[amount] == INT_MAX) {
            return -1;
        }
        return dp[amount];
    }
};

3. 力扣279.完全平方数

3.1 分析

1.确定dp数组以及下标的含义

dp[j]:和为j的完全平方数的最小数量为dp[j]

2.确定递推公式

dp[j]可以由dp[j - i * i]推出,dp[j - i * i] + 1可以凑成dp[j]

需要选择最小的dp[j]

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

3.dp数组如何初始化

由递推公式dp[j] = min(dp[j - i*i]+1,dp[j])可知每次选择最小的,故非0下标的dp[j]一定要初始为最大值,这样dp[j]在递推的时候才不会被初始值覆盖。

4.确定遍历顺序

如果求组合数就是外层for循环遍历物品,内层for遍历背包。

如果求排列数就是外层for遍历背包,内层for循环遍历物品。

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

5.举例推导dp数组

算法学习day45_第3张图片

3.2 代码

class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1, INT_MAX); // 初始化dp数组,dp[i]表示组成i所需的最少平方数个数
        dp[0] = 0; // 初始化dp[0]为0,表示组成0不需要平方数
        for (int i = 1; i <= n; i++) { // 遍历背包,即遍历目标数
            for (int j = 1; j * j <= i; j++) { // 遍历物品,即平方数
                dp[i] = min(dp[i - j * j] + 1, dp[i]); // 转移方程,dp[i-j*j]+1表示当前数减去一个平方数后,组成剩余数所需的平方数个数+1
            }
        }
        return dp[n]; // 返回组成n所需的最少平方数个数
    }
};

4.参考资料

[代码随想录]

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