携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情
题目:LeetCode
在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。
每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。
注意,一开始你手头没有任何零钱。
给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。
示例 1:
输入:bills = [5,5,5,10,20]
输出:true
解释:
前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。
第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。
第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零,所以我们输出 true。
示例 2:
输入:bills = [5,5,10,10,20]
输出:false
解释:
前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。
对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。
对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。
由于不是每位顾客都得到了正确的找零,所以答案是 false。
提示:
1 <= bills.length <= 105bills[i]不是5就是10或是20
解题思路
从题目场景和给出的示例,初看可能就是摸不着头脑,要怎么操作能保证每一位顾客都得到正确找零呢?
仔细分析下题干信息,可供判断的情况很少
需维护好三种金额的数量5,10和20。
有如下三种情况:
- 账单是5,直接收下;
- 账单是10,消耗一个5,增加一个10
- 账单是20,优先消耗一个10和一个5,若不够,再消耗三个5
其实上面两种情形都是固定策略,不需要做特别分析,而唯一不确定的其实是最后一种情形。
顾客付账为20的情况,为何优先消耗一个10和一个5呢?
10只能给20找零,而5可以给10和20找零,说明5更万能
小范围内最优:遇到20,优先消耗10,正常完成找零。整体最优:就是完成全部的找零。
代码实现
public boolean lemonadeChange(int[] bills) {
int five = 0; // 记录5元的数目
int ten = 0; // 记录10元的数目
// 遍历数组 bills
for (int i = 0; i < bills.length; i++) {
if (bills[i] == 5) {
five++;
} else if (bills[i] == 10) { // 如果给10, 那找5
five--;
ten++;
} else if (bills[i] == 20) {
if (ten > 0) {
ten--;
five--;
} else {
five -= 3;
}
}
if (five < 0 || ten < 0) return false;
}
return true;
}
首先确定的一点就是,找零只会涉及到5和10两个面值, 20是不会参与找零。这里就可以分三种情况来处理:
- 如果给5,直接 five 加1;
- 如果给10,那就five 减1,ten 加1,没有5的情况直接返回 false;
- 如果为20,那肯定优先 ten 减1,five 同样减1; 没有ten 时,找回3个5;到最后就是都符合要求了。
主要思路就是分析上面三种情形。
运行结果
复杂度分析
- 时间复杂度
- 空间复杂度
在掘金(JUEJIN) 一起分享知识, Keep Learning!