还没面试,国企HR把我删了??
这网友投了个国企,面试还没影呢,HR先加微信,问得那叫一个细。本硕哪儿读的,籍贯哪儿,家里啥情况,感觉不像招人,像查户口。
问完一句“OK同学,等通知”,人就消失了。等了两周,一点动静没有,网友想着问问进度吧,结果消息一发:被对方拒收。
好家伙,面都没见上,先被删了。
最扎心的是后面才听说,人家岗位可能早就内定好了,加你微信就是补个流程,材料凑一凑,样子做一做,最后统一清场。
这就很离谱了。你说不合适就不合适,发个模板拒信也行啊,直接删人是什么操作?打工人还在那儿认真准备,HR那边已经开始打扫战场了。
合着不是候选人,是流程里的背景板。HR删得挺快,尊重倒是一点没加载出来。
第一位顾客掏 10 块,你手里一张 5 块都没有,收银台当场就炸。
这就是「柠檬水找零」这题最容易被写复杂的地方。它不是让你算有多少种找零方案,也不是让你回溯所有可能。每杯柠檬水 5 块,顾客只会给 5、10、20。你手里能不能一路找下去,只看两张钞票的库存:5 块和 10 块。
我写这题时,一般不会上来就建什么零钱数组。因为 20 块不用存,收到 20 只是收入,不参与后面找零。真正有用的只有 5 和 10。
现场逻辑是这样:
收到 5 块,直接收下。
收到 10 块,必须找 5 块。没有 5 块,失败。
收到 20 块,要找 15 块。这里我会优先用一张 10 加一张 5,而不是三张 5。
为什么?
因为 5 块太关键了。后面不管遇到 10 还是 20,都离不开 5。你为了找一个 20,把三张 5 全掏出去,后面来个 10 就直接死。
代码可以写得很短:
deflemonade_change(bills):
five = 0
ten = 0
for idx, pay in enumerate(bills):
if pay == 5:
five += 1
elif pay == 10:
if five == 0:
returnFalse
five -= 1
ten += 1
else: # pay == 20
if ten > 0and five > 0:
ten -= 1
five -= 1
elif five >= 3:
five -= 3
else:
returnFalse
returnTrue
拿一组数据走一下:
orders = [5, 5, 5, 10, 20]
print(lemonade_change(orders))
这组能过。
过程大概是这样:
前面三个 5 收进来,手里有 3 张 5。 第 4 个顾客给 10,找出去 1 张 5,手里剩 2 张 5,多了 1 张 10。 第 5 个顾客给 20,优先用 10 + 5 找零,刚好。
再看一个容易翻车的:
orders = [5, 5, 10, 10, 20]
print(lemonade_change(orders))
这个返回 False。
很多人第一眼觉得前面收了不少钱,应该够找。这个判断不对。收银台不是看总金额,是看面额结构。
走到最后一个 20 时,手里有两张 10,但是只有 0 张 5。要找 15,必须带一张 5,不然两张 10 加起来是 20,没法硬找。
这题的坑就在这里:钱够,不代表能找开。
如果想看得更清楚,可以加一个排查版,把失败位置打出来:
defcheck_counter(bills):
box = {5: 0, 10: 0}
for i, pay in enumerate(bills):
if pay == 5:
box[5] += 1
elif pay == 10:
if box[5] < 1:
print("failed at", i, "pay=10", box)
returnFalse
box[5] -= 1
box[10] += 1
else:
if box[10] >= 1and box[5] >= 1:
box[10] -= 1
box[5] -= 1
elif box[5] >= 3:
box[5] -= 3
else:
print("failed at", i, "pay=20", box)
returnFalse
returnTrue
算法复杂度没什么花活。
每个顾客只处理一次,时间复杂度是 O(n)。只用了两个计数变量,空间复杂度是 O(1)。
这题真正要记住的不是代码,而是那个取舍:找 20 的时候,能用 10 + 5 就别用 5 + 5 + 5。后面还要不要活,就看你手里留没留 5 块。