优化问题经典例子:找零时使用最少数量的硬币。
假设某漂亮国小区24小时自动售货机每笔现金交易(暂不支持移动支付)找零时使用最少数量的硬币以减少硬币补充次数节省成本。
例如,张三使用一元大钞(1元=100分)购买了总共价值37分的榨菜、茶叶蛋和肥仔快乐水,假设硬币面值有1分、5分、10分和25分,那么应该找回多少个硬币呢?
答案是6枚:25 分的 2 枚,10 分的 1 枚,1 分的 3 枚。
如何计算呢?
从面值最大的硬币(25 美分)开始,使用尽可能多的硬币,然后尽可能多地使用面 值第 2 大的硬币。这种方法叫作贪婪算法——试图最大程度地解决问题。
用Golang实现的贪婪算法下的找零时使用最少数量的硬币的代码如下:
package main
import (
"fmt"
"sort"
)
func minCoinsGreed(coinValus []int, change int) int {
// 找零时使用最少数量硬币:贪婪算法
// 从面值最大的硬币(25 美分)开始,使用尽可能多的硬币,
// 然后尽可能多地使用面值第 2 大的硬币。
// 确保硬币面值降序排序
sort.Sort(sort.Reverse(sort.IntSlice(coinValus)))
coins := 0
for _, va := range coinValus {
// 商表示可以使用此面值的硬币数量
div := change / va
// 累计硬币数量
coins += div
// 余数为还需要找零的面值
change = change % va
// 如果已找零完毕则提前退出循环
if change == 0 {
break
}
}
return coins
}
func main() {
coinValues := []int{25, 10, 5, 1}
fmt.Println("需要的硬币数量:", minCoinsGreed(coinValues, 63))
// 需要的硬币数量: 6
coinValus = []int{25, 21, 10, 5, 1}
fmt.Println("需要的硬币数量:", minCoinsGreed(coinValues, 63))
// 需要的硬币数量: 6
}
如果找零面值里面支持21分,按照此贪婪算法计算出来的结果却是6枚。
实际最少硬币数量应该是3枚21分的硬币即可。
所以此贪婪算法在计算找零最少硬币数量未必得到最优解。
要一定得到最优解,下一篇将尝试优雅的递归解决硬币找零。