1. 问题背景与需求分析
在街边经营柠檬水摊时,我们经常会遇到顾客用不同面额钞票支付的情况。每杯柠檬水售价固定为5元,顾客可能用5元、10元或20元钞票支付,我们需要准确判断能否在不透支零钱的情况下完成找零。这就是LeetCode 860题"柠檬水找零"的核心场景。
这个问题看似简单,实则考察了我们在有限资源条件下做出最优决策的能力。作为摊主,我们需要实时维护当前持有的零钱数量,并在每个交易发生时快速判断:
- 能否完成当前交易的找零
- 如何优先使用大面额零钱(策略性保留小面额)
- 在什么情况下应该直接拒绝交易
实际编码中,我们需要处理钞票面额的优先级(例如收到20元时应优先找10+5而非3张5元),这正是贪心算法的典型应用场景。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 算法设计与核心思路
2.1 贪心算法选择依据
选择贪心算法解决这个问题主要基于以下三个特性:
- 局部最优性:每个找零步骤只需考虑当前最优解(尽量保留更多5元)
- 无后效性:当前找零决策不会影响后续决策的正确性
- 子问题重叠:每个交易可以视为独立的子问题
贪心策略具体表现为:
- 收到5元:直接收下,无需找零
- 收到10元:找一张5元(没有则失败)
- 收到20元:优先找10+5组合,其次考虑3张5元(因为5元更灵活)
关键提示:20元找零时必须优先消耗10元,保留更多5元。这是通过反证法可以证明的最优策略——如果选择找3张5元而保留10元,可能在后续遇到多个10元支付时无法找零。
2.2 数据结构选择
使用两个计数器(five和ten)比维护数组更高效:
python复制class Solution:
def lemonadeChange(self, bills: List[int]) -> bool:
five = ten = 0
for bill in bills:
if bill == 5:
five += 1
elif bill == 10:
if not five: return False
five -= 1
ten += 1
else:
if ten and five: # 优先10+5组合
ten -= 1
five -= 1
elif five >= 3: # 次选3*5
five -= 3
el
