题目描述

image.png

解题思路

但仔细一琢磨就会发现,可供我们做判断的空间非常少!
只需要维护三种金额的数量,5,10和20。
有如下三种情况:

  • 情况一:账单是5,直接收下。
  • 情况二:账单是10,消耗一个5,增加一个10
  • 情况三:账单是20,优先消耗一个10和一个5,如果不够,再消耗三个5

此时大家就发现 情况一,情况二,都是固定策略,都不用我们来做分析了,而唯一不确定的其实在情况三。
而情况三逻辑也不复杂甚至感觉纯模拟就可以了,其实情况三这里是有贪心的。
账单是20的情况,为什么要优先消耗一个10和一个5呢?
因为美元10只能给账单20找零,而美元5可以给账单10和账单20找零,美元5更万能!
所以局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。
局部最优可以推出全局最优,并找不出反例,那么就试试贪心算法!

  1. public boolean lemonadeChange(int[] bills) {
  2. int five = 0, ten = 0, twenty = 0;
  3. for (int bill : bills) {
  4. if (bill == 5) {
  5. five++;
  6. }
  7. if (bill == 10) {
  8. if (five <= 0) return false;
  9. five--;
  10. ten++;
  11. }
  12. if (bill == 20) {
  13. // 优先消耗10美元,因为5美元的找零用处更大,能多留着就多留着(这里体现了贪心的策略)
  14. // 局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。
  15. if (ten > 0 && five > 0) {
  16. ten--;
  17. five--;
  18. twenty++;
  19. }
  20. else if (ten == 0 && five >= 3) {
  21. five = five - 3;
  22. }
  23. else return false;
  24. }
  25. }
  26. return true;
  27. }