0%

零钱兑换

零钱兑换

在刷Leetcode的时候发现了零钱兑换的两题,两题都是属于背包问题,但是又有所不同,虽然背包问题已经总结了一下但还是想总结一下这两题

322.零钱兑换

题目描述

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

示例 1:

1
2
3
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1

示例 2:

1
2
输入: coins = [2], amount = 3
输出: -1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

代码

主要写一下背包思想的解法,其他的可以参考:https://leetcode-cn.com/problems/coin-change/solution/dong-tai-gui-hua-shi-yong-wan-quan-bei-bao-wen-ti-/

可以看的出来这个零钱兑换很像完全背包问题

类似的地方:

  • 完全背包问题背包有体积,这里对应着总金额amount
  • 完全背包中有各种物品,这里对应着硬币coins
  • 完全背包中各种物品数量无限,在这里硬币的数量也无限

不同之处:

  • 完全背包的目的是在体积允许的范围内,拿走价值更多的物品;这里是在amount允许的范围里,需要硬币数量最少
  • 完全背包最终背包不需要被填满,这里最终硬币总金额需要等于amount

所以最终我们模仿完全背包的公式,dp[i] 表示amount为i时,可以凑成总金额所需的最少的硬币个数(与背包中dp[i]表示价格最大形成对比),然后就可以得出答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public int coinChange(int[] coins, int amount) {
// dp[i] 表示amount为i时,可以凑成总金额所需的最少的硬币个数。
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount + 1);
dp[0] = 0;

for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}

if (dp[amount] == amount + 1) {
dp[amount] = -1;
}
return dp[amount];
}
}

一开始我就想借鉴背包思想解决这题,但是我过于纠结体积和价值,一直用的是max导致最终没能完成,其实现在跳出来想想这个min才是恰到好处,也体现着背包思想,是我自己太过死板。

518.零钱兑换II

题目描述

给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。

示例 1:

1
2
3
4
5
6
7
输入: amount = 5, coins = [1, 2, 5]
输出: 4
解释: 有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

示例 2:

1
2
3
4
5
6
7
输入: amount = 3, coins = [2]
输出: 0
解释: 只用面额2的硬币不能凑成总金额3。
示例 3:

输入: amount = 10, coins = [10]
输出: 1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change-2
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

代码

这题就比较简单了,因为在做背包问题的时候刚好做过,也是类似填表格的方法,详情可以看:https://www.cnblogs.com/zhou-ning/articles/13222220.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public int change(int amount, int[] coins) {
if (coins == null || coins.length == 0) {
if (amount==0) {
return 1;
}
return 0;
}
// 代表次数
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int i = 0; i < coins.length; i++) {
// 正序
for (int j = coins[i]; j < dp.length; j++) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}