194 lines
6.5 KiB
Markdown
194 lines
6.5 KiB
Markdown
<p align="center">
|
||
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||
<a href="https://img-blog.csdnimg.cn/20201210231711160.png"><img src="https://img.shields.io/badge/公众号-代码随想录-brightgreen" alt=""></a>
|
||
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
|
||
</p>
|
||
<p align="center"><strong>欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||
|
||
|
||
## 860.柠檬水找零
|
||
|
||
题目链接:https://leetcode-cn.com/problems/lemonade-change/
|
||
|
||
在柠檬水摊上,每一杯柠檬水的售价为 5 美元。
|
||
|
||
顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。
|
||
|
||
每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。
|
||
|
||
注意,一开始你手头没有任何零钱。
|
||
|
||
如果你能给每位顾客正确找零,返回 true ,否则返回 false 。
|
||
|
||
示例 1:
|
||
输入:[5,5,5,10,20]
|
||
输出:true
|
||
解释:
|
||
前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。
|
||
第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。
|
||
第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。
|
||
由于所有客户都得到了正确的找零,所以我们输出 true。
|
||
|
||
示例 2:
|
||
输入:[5,5,10]
|
||
输出:true
|
||
|
||
示例 3:
|
||
输入:[10,10]
|
||
输出:false
|
||
|
||
示例 4:
|
||
输入:[5,5,10,10,20]
|
||
输出:false
|
||
解释:
|
||
前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。
|
||
对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。
|
||
对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。
|
||
由于不是每位顾客都得到了正确的找零,所以答案是 false。
|
||
|
||
提示:
|
||
|
||
* 0 <= bills.length <= 10000
|
||
* bills[i] 不是 5 就是 10 或是 20
|
||
|
||
## 思路
|
||
|
||
这是前几天的leetcode每日一题,感觉不错,给大家讲一下。
|
||
|
||
这道题目刚一看,可能会有点懵,这要怎么找零才能保证完整全部账单的找零呢?
|
||
|
||
**但仔细一琢磨就会发现,可供我们做判断的空间非常少!**
|
||
|
||
只需要维护三种金额的数量,5,10和20。
|
||
|
||
有如下三种情况:
|
||
|
||
* 情况一:账单是5,直接收下。
|
||
* 情况二:账单是10,消耗一个5,增加一个10
|
||
* 情况三:账单是20,优先消耗一个10和一个5,如果不够,再消耗三个5
|
||
|
||
此时大家就发现 情况一,情况二,都是固定策略,都不用我们来做分析了,而唯一不确定的其实在情况三。
|
||
|
||
而情况三逻辑也不复杂甚至感觉纯模拟就可以了,其实情况三这里是有贪心的。
|
||
|
||
账单是20的情况,为什么要优先消耗一个10和一个5呢?
|
||
|
||
**因为美元10只能给账单20找零,而美元5可以给账单10和账单20找零,美元5更万能!**
|
||
|
||
所以局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。
|
||
|
||
局部最优可以推出全局最优,并找不出反例,那么就试试贪心算法!
|
||
|
||
C++代码如下:
|
||
|
||
```C++
|
||
class Solution {
|
||
public:
|
||
bool lemonadeChange(vector<int>& bills) {
|
||
int five = 0, ten = 0, twenty = 0;
|
||
for (int bill : bills) {
|
||
// 情况一
|
||
if (bill == 5) five++;
|
||
// 情况二
|
||
if (bill == 10) {
|
||
if (five <= 0) return false;
|
||
ten++;
|
||
five--;
|
||
}
|
||
// 情况三
|
||
if (bill == 20) {
|
||
// 优先消耗10美元,因为5美元的找零用处更大,能多留着就多留着
|
||
if (five > 0 && ten > 0) {
|
||
five--;
|
||
ten--;
|
||
twenty++; // 其实这行代码可以删了,因为记录20已经没有意义了,不会用20来找零
|
||
} else if (five >= 3) {
|
||
five -= 3;
|
||
twenty++; // 同理,这行代码也可以删了
|
||
} else return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
};
|
||
```
|
||
|
||
## 总结
|
||
|
||
咋眼一看好像很复杂,分析清楚之后,会发现逻辑其实非常固定。
|
||
|
||
这道题目可以告诉大家,遇到感觉没有思路的题目,可以静下心来把能遇到的情况分析一下,只要分析到具体情况了,一下子就豁然开朗了。
|
||
|
||
如果一直陷入想从整体上寻找找零方案,就会把自己陷进去,各种情况一交叉,只会越想越复杂了。
|
||
|
||
|
||
## 其他语言版本
|
||
|
||
|
||
Java:
|
||
```java
|
||
class Solution {
|
||
public boolean lemonadeChange(int[] bills) {
|
||
int cash_5 = 0;
|
||
int cash_10 = 0;
|
||
|
||
for (int i = 0; i < bills.length; i++) {
|
||
if (bills[i] == 5) {
|
||
cash_5++;
|
||
} else if (bills[i] == 10) {
|
||
cash_5--;
|
||
cash_10++;
|
||
} else if (bills[i] == 20) {
|
||
if (cash_10 > 0) {
|
||
cash_10--;
|
||
cash_5--;
|
||
} else {
|
||
cash_5 -= 3;
|
||
}
|
||
}
|
||
if (cash_5 < 0 || cash_10 < 0) return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
}
|
||
```
|
||
|
||
Python:
|
||
```python
|
||
class Solution:
|
||
def lemonadeChange(self, bills: List[int]) -> bool:
|
||
five, ten, twenty = 0, 0, 0
|
||
for bill in bills:
|
||
if bill == 5:
|
||
five += 1
|
||
elif bill == 10:
|
||
if five < 1: return False
|
||
five -= 1
|
||
ten += 1
|
||
else:
|
||
if ten > 0 and five > 0:
|
||
ten -= 1
|
||
five -= 1
|
||
twenty += 1
|
||
elif five > 2:
|
||
five -= 3
|
||
twenty += 1
|
||
else:
|
||
return False
|
||
return True
|
||
|
||
```
|
||
|
||
Go:
|
||
|
||
|
||
|
||
|
||
-----------------------
|
||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|