柠檬水找零
- https://leetcode.cn/problems/lemonade-change/
描述
-
在柠檬水摊上,每一杯柠檬水的售价为 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 <= 10510^5105
- bills[i] 不是 5 就是 10 或是 20
Typescript 版算法实现
1 )一般思路
function lemonadeChange(bills: number[]): boolean {
// 表示自己的钱箱(用于存储零钱)
const box: number[] = [];
// 判断是否有顾客还在
while (bills.length) {
// 取出当前排在最前面顾客的钱
const money: number = bills.shift();
// 这种情况不需要找零
if (money === 5) {
box.push(money);
} else {
// 手里的零钱要降序排列也就说最大的面值的钱放在最前面
box.sort((a, b) => b - a);
// 顾客的钱减去饮料的钱就是需要找给顾客的零钱
let change = money - 5;
for (let i = 0, len = box.length; i < len; i++) {
if (box[i] <= change) {
change -= box[i];
box.splice(i, 1);
// 删除了元素,数组的长度发生了变化,要维持刚才的i不变
i--;
}
if (change === 0) break;
}
// 没有足够的零钱找给顾客
if (change !== 0) return false;
// 顾客的钱存起来
box.push(money);
}
}
return true;
};
- 这种贪心策略,没有任何技巧
- 这种算法耗时很严重,时间复杂度 O(n2lognn^2lognn2logn)
- 上面这种思路就很复杂了,不推荐这种算法
2 )分类讨论
function lemonadeChange(bills: number[]): boolean {
// 准备 5元,10元面值的钱,用于标识是否有对应的零钱
let five: number = 0, ten: number = 0;
// 遍历所有的客户付款
for (const bill of bills) {
// 匹配客户付款5元的场景: 不用找零
if (bill === 5) {
five += 1;
// 匹配客户付款10元的场景: 找零5元,进账10元
} else if (bill === 10) {
if (five === 0) return false;
five -= 1;
ten += 1;
// 匹配客户付款20元的场景: 找零15,进账20(不用处理, 这20元无法用于找零), 有两种情况
} else {
// 情况1: 5元和10元的组合
if (five > 0 && ten > 0) {
five -= 1;
ten -= 1;
// 情况2: 没有10元的情况下, 使用三张5元的
} else if (five >= 3) {
five -= 3;
// 否则找零失败,返回 false
} else return false;
}
}
return true;
};
- 这种是官方提供思路
- 由于顾客只可能给你三个面值的钞票,而且我们一开始没有任何钞票
- 因此我们拥有的钞票面值只可能是 5 美元,10 美元和 20 美元三种
- 我们所能找零的面值也就只有 5 美元 和 10美元 两种面值的组合
- 基于分类讨论的方式,列举了可能得找零场景,一个循环就搞定
- 时间复杂度:O(N),其中 N 是 bills 的长度
- 空间复杂度:O(1),常数空间,只用了2个变量,所以是O(1)
- 备注: O(2)也用O(1)来表示,常数都是O(1)
Python3 版算法实现
1 ) 方案1
class Solution:
def lemonadeChange(self, bills: List[int]) -> bool:
# 表示自己的钱箱(用于存储零钱)
box = []
# 判断是否有顾客还在
while bills:
# 取出当前排在最前面顾客的钱
money = bills.pop(0)
# 这种情况不需要找零
if money == 5:
box.append(money)
else:
# 手里的零钱要降序排列也就说最大的面值的钱放在最前面
box.sort(reverse=True)
# 顾客的钱减去饮料的钱就是需要找给顾客的零钱
change = money - 5
i = 0
while change > 0 and i < len(box):
if box[i] <= change:
change -= box[i]
box.pop(i)
else:
i += 1
# 没有足够的零钱找给顾客
if change != 0:
return False
# 顾客的钱存起来
box.append(money)
return True
2 ) 方案2
class Solution:
def lemonadeChange(self, bills: List[int]) -> bool:
# 准备 5元,10元面值的钱,用于标识是否有对应的零钱
five = 0
ten = 0
# 遍历所有的客户付款
for bill in bills:
# 匹配客户付款5元的场景: 不用找零
if bill == 5:
five += 1
# 匹配客户付款10元的场景: 找零5元,进账10元
elif bill == 10:
if five == 0:
return False
five -= 1
ten += 1
# 匹配客户付款20元的场景: 找零15,进账20(不用处理, 这20元无法用于找零), 有两种情况
elif bill == 20:
# 情况1: 5元和10元的组合
if five > 0 and ten > 0:
five -= 1
ten -= 1
# 情况2: 没有10元的情况下, 使用三张5元的
elif five >= 3:
five -= 3
# 否则找零失败,返回 false
else:
return False
return True
Golang 版算法实现
1 ) 方案1
func lemonadeChange(bills []int) bool {
// 表示自己的钱箱(用于存储零钱)
box := []int{}
// 判断是否有顾客还在
for len(bills) > 0 {
// 取出当前排在最前面顾客的钱
money := bills[0]
bills = bills[1:]
// 这种情况不需要找零
if money == 5 {
box = append(box, money)
} else {
// 手里的零钱要降序排列也就说最大的面值的钱放在最前面
sort.Sort(sort.Reverse(sort.IntSlice(box)))
// 顾客的钱减去饮料的钱就是需要找给顾客的零钱
change := money - 5
for i := 0; i < len(box); i++ {
if box[i] <= change {
change -= box[i]
box = append(box[:i], box[i+1:]...)
// 删除了元素,数组的长度发生了变化,要维持刚才的i不变
i--
}
if change == 0 {
break
}
}
// 没有足够的零钱找给顾客
if change != 0 {
return false
}
// 顾客的钱存起来
box = append(box, money)
}
}
return true
}
2 ) 方案2
// lemonadeChange 检查是否可以成功找零
func lemonadeChange(bills []int) bool {
// 准备 5元,10元面值的钱,用于标识是否有对应的零钱
five, ten := 0, 0
// 遍历所有的客户付款
for _, bill := range bills {
// 匹配客户付款5元的场景: 不用找零
if bill == 5 {
five++
// 匹配客户付款10元的场景: 找零5元,进账10元
} else if bill == 10 {
if five == 0 {
return false
}
five--
ten++
// 匹配客户付款20元的场景: 找零15,进账20(不用处理, 这20元无法用于找零), 有两种情况
} else {
// 情况1: 5元和10元的组合
if five > 0 && ten > 0 {
five--
ten--
// 情况2: 没有10元的情况下, 使用三张5元的
} else if five >= 3 {
five -= 3
// 否则找零失败,返回 false
} else {
return false
}
}
}
return true
}
1万+



被折叠的 条评论
为什么被折叠?



