代码随想录刷题day45| 零钱兑换&完全平方数


day45学习内容

day45主要内容

  • 零钱兑换
  • 完全平方数

声明
本文思路和文字,引用自《代码随想录》


一、零钱兑换

322.原题链接

1.1、动态规划五部曲

1.1.1、 确定dp数组(dp table)以及下标的含义

-  p[i]表示凑成金额i所需的最少硬币数。

1.1.2、确定递推公式

最少嘛,你就要想到min。和零钱兑换II有一点区别就是那一题求取所有的排列数,那一题已经把所有的求出来了,所以这一题,很自然的想到,要取一下min(dp[j],dp[j-nums[i]+1])

dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);

1.1.3、 dp数组如何初始化

dp[0] = 0;

1.1.4、确定遍历顺序

先遍历物品后遍历背包。并且是正序的,因为正序是表示可重复的。

1.2、代码

class Solution {
    public int coinChange(int[] coins, int amount) {
        int max = Integer.MAX_VALUE;
        int[] dp = new int[amount + 1];
        // 每个元素初始化为max,表示初始时没有任何一种硬币组合能够凑成对应的金额。
        for (int j = 0; j < dp.length; j++) {
            dp[j] = max;
        }
        // 初始化dp[0],为啥等于0.因为当金额为0时需要的硬币数目为0
        dp[0] = 0;
        for (int i = 0; i < coins.length; i++) {
            // 先遍历物品再遍历背包
            for (int j = coins[i]; j <= amount; j++) {
                if (dp[j - coins[i]] != max) {
                    // 选择硬币数目最小的情况
                    dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
                }
            }
        }
        // 如果dp[amount]等于max,说明没有任何一种硬币组合能够凑成总金额,因此返回-1;
        // 否则,返回dp[amount],即凑成总金额所需的最少硬币数。
        return dp[amount] == max ? -1 : dp[amount];
    }
}

1.2.1、如何理解状态转移方程?

外层循环遍历所有给定的硬币面额,内层循环从当前硬币面额开始,直到总金额amount。对于内层循环中的每一个金额j,代码首先检查j减去当前硬币面额的结果(即dp[j - coins[i]])是否已经有了一个解(不是max),如果是,表示j金额可以通过加上一个当前面额的硬币得到。然后,通过Math.min(dp[j], dp[j - coins[i]] + 1)更新dp[j],即比较当前的最少硬币数和通过当前面额的硬币得到的硬币数+1哪个更小,选择较小的一个作为新的最少硬币数

1.2.2、为什么dp[j - coins[i]] + 1要+1

假设你已经知道了对于金额j-coins[i](即当前考虑的总金额减去一枚当前面额的硬币),最少需要dp[j - coins[i]]枚硬币。那么,如果你向这个组合中再加上一枚coins[i]面额的硬币,就可以得到金额j。因此,凑成金额j所需的最少硬币数就可以通过凑成金额j-coins[i]所需的硬币数加上这一枚新加入的硬币来计算,即dp[j - coins[i]] + 1

这里的+1正是代表加上这一枚新硬币。

举一个简单的例子,假设你有面额为1的硬币,你要凑成金额3。按照动态规划的过程,你会这样计算:

  • 凑成金额0需要0枚硬币,即dp[0] = 0
  • 凑成金额1需要dp[0] + 1 = 1枚硬币。
  • 凑成金额2需要dp[1] + 1 = 2枚硬币。
  • 凑成金额3需要dp[2] + 1 = 3枚硬币。

每次+1就是代表往当前的金额中添加一枚当前考虑的硬币,从而达到新的金额。这就是为什么要+1。

二、完全平方数

279.原题链接

完全平方数就是物品且可以无限使用,凑个正整数n就是背包,问凑满这个背包最少需要多少物品?

2.1、动态规划五部曲

2.1.1、 确定dp数组(dp table)以及下标的含义

-  dp[j]表示和为j的完全平方数的最少数量为dp[j]

2.1.2、确定递推公式

dp[j] = Math.min(dp[j], dp[j - i * i] + 1);

2.1.3、 dp数组如何初始化

dp[0] = 0;

2.1.4、确定遍历顺序

先遍历背包,再遍历物品。或者先遍历背包,再遍历物品都可以。

2.1.5、计算并返回最终结果

return dp[n];

2.2、代码

class Solution {
    public int numSquares(int n) {
        int max = Integer.MAX_VALUE;
        int[] dp = new int[n + 1];
        // 初始化
        for (int j = 0; j <= n; j++) {
            dp[j] = max;
        }

        dp[0] = 0;
        // 先遍历物品后遍历
        for (int i = 1; i * i <= n; i++) {
            for (int j = i * i; j <= n; j++) {
                if (dp[j - i * i] != max) {
                    dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
                }
            }
        }
        return dp[n];
    }
}

总结

1.感想

  • 疯狂补清明假期拉下的进度。。

2.思维导图

本文思路引用自代码随想录,感谢代码随想录作者。

  • 26
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值