注册

leetcode-零钱兑换

周末一直在下雨,甚至看天气预报,年前就一直是这样的天气了。不过这样的天气也有好处,反正哪儿也去不了,就在家看看书,也算是难得精心。


题目


给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。



示例 1:

输入:coins = [1, 2, 5], amount = 11

输出: 3

解释: 11 = 5 + 5 + 1




示例 2:

输入:coins = [2], amount = 3

输出: -1




示例 3:

输入:coins = [1], amount = 0

输出: 0




示例 4:

输入:coins = [1], amount = 11

输出: 1




示例 5:

输入:coins = [1], amount = 2

输出: 2



思路


这也是一个背包问题,要求刚好把背包装满,选用尽量少的件数。

定义一个一维数组dp,dp[n]代表总金额为n的情况下,最少的硬币个数,如果无法刚好凑成n,那么可以用一个特殊的固定值。dp[n] = min(dp[n-coin[k]]) + 1

怎么理解呢?

我们可以这么考虑:刚好组成总金额n的硬币中,可能包含coin[0]~coin[len-1]各有ci枚,当然,ci可以是0。如果ci > 0,那么我们可以先去掉这一枚,这样,dp[n] = dp[n-coin[k]] + 1;因为有len枚硬币,这里就可能存在len种情况,所以,dp[n] = min(dp[n-coin[0]]+1...dp[n-coin[len-1]]+1),整理一下,就得到了上面的状态转移方程。

边界条件,amount为0的时候,我们可以不用任何1枚硬币,所以dp[0] = 0。

另外,对于n无法刚好凑成的情况,本来我们可以初始化dp[n] = Integer.MAX_VALUE,由于有+1这个操作,会导致溢出,所以我们选择把dp[n]初始化成amount+1,因为面值是整数,至少是1,所以对于能凑成的n,硬币个数一定小于amount+1,等于amount+1的,就代表无法凑成。


Java版本代码


class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int coin : coins) {
if (i >= coin) {
dp[i] = Integer.min(dp[i], dp[i-coin] + 1);
}
}
}
if (dp[amount] > amount) {
return -1;
}
return dp[amount];
}
}

作者:podongfeng
链接:https://juejin.cn/post/7056389501618225165
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册