贪心算法案例 - 零钱兑换问题
贪心算法原则:
- 每一次都选取当前最优解
- 《向前看,别回头》
题目描述:
给你一个整数数组
coins
,表示不同面额的硬币;以及一个整数amount
,表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回
-1
。你可以认为每种硬币的数量是无限的。
注意,局部最优解并不能保证全局最优解!
如下面的例子:
- 示例1
coins {15, 10, 1}
总金额21的情况下:
1*15 + 6*1 = 21 ==> 7个硬币(贪心思路)
2*10 + 1*1 = 21 => 3个硬币(实际最优解)
- 示例2
coins {15, 10}
总金额为20的情况下:
1*15 + ? ==> 无解(贪心思路)
2*10 = 20 ==> 实际情况有解
使用贪心的思想求解零钱兑换问题
public int coinChange(int[] coins, int amount) {
// 每次循环时找到当前最优解: 面值最大的硬币,它凑出的硬币数最小
int remainder = amount; // 记录剩余金额
int count = 0; // 记录硬币的数量
// 将硬币中的面值由大到小排序,确保每次拿到的都是当前最大面值的硬币!
/**
* 注意这里为什么在while循环条件里不写 >= ,
* 条件刚好是 remainder = coin表示刚好凑够,此时本应该跳出循环了,
* 但是remainder >= coin 该条件都成立时都会跳出循环,逻辑上是有问题的,
* 因此把 remainder = coin 这个条件单独拿出来做退出操作
*
* for (int coin : coins) {
* while (remainder >= coin) { // 剩余金额 > 最大金额
* remainder -= coin;
* count++;
* // 此处的break只会退出while循环,并不会退出for循环,需要特别注意
* // 如果此时条件 remainder = coin 其实也可以,只是会造成后面的for循环遍历部分空转,但不推荐这样写
* break;
* }
* }
*
*/
for (int coin : coins) {
while (remainder > coin) { // 剩余金额 > 最大金额
remainder -= coin;
count++;
}
// 剩余金额 = 当前硬币面值 ==> 需要退出整个for循环
if (remainder == coin) {
remainder = 0;
count++;
break;
}
}
// 整个循环结束后还没凑够
if (remainder > 1) {
return -1;
}
return count;
}
标签:硬币,int,coins,零钱,算法,coin,remainder,贪心
From: https://www.cnblogs.com/lilyflower/p/18462037