算法-贪心篇10-柠檬水找零

柠檬水找零

力扣题目链接

题目描述

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。
每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。
注意,一开始你手头没有任何零钱。
给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

解题思路

很简单,因为钱只有三种面值,我们只需要一个长度为三的数组来存储自己所拥有的零钱的数量就行。(其实两个就够了,因为找零只会使用到5和10,但是工程思想,都保存下来没毛病)
每次收钱就从零钱里面试着找零就行。

题解

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        vector<int> haveChange(3, 0);
        for(int i = 0; i < bills.size(); i++){
            if(bills[i] == 5){
                haveChange[0]++;
            }else if(bills[i] == 10){
                if(haveChange[0] > 0){
                    haveChange[0]--;
                    haveChange[1]++;
                }
                else{
                    return false;
                }
            }else if(bills[i] == 20){
                if(haveChange[1] > 0 && haveChange[0] > 0){
                    haveChange[0]--;
                    haveChange[1]--;
                    haveChange[2]++;
                }
                else if(haveChange[0] >= 3){
                    haveChange[0] -= 3;
                    haveChange[2]++;
                }
                else{
                    return false;
                }
            }
        }

        return true;
    }
};
<think>好的,我现在需要解决用户关于C++实现柠檬水找零算法的问题。首先,我得理解这个问题。柠檬水找零的问题是说,每个顾客买柠檬水付5美元、10美元或20美元,必须正确找零。一开始没有零钱,所以如果第一个顾客付的不是5美元,就无法找零,直接返回false。接下来,我需要参考用户提供的引用内容,看看其他解决方案是怎么处理的。用户给了五个引用,都是关于这个问题的C++代码。我需要综合这些代码,找出共同点和最佳实践。 首先,所有引用中都使用了贪心算法贪心的策略是优先用大面额的零钱来找零,比如当收到20美元时,尽量先用10和5的组合,如果没有10再用三个5。这是因为10美元只能用于找零20的情况,而5美元更灵活。所以,在处理20美元时,应该先检查是否有10和5,没有的话再用三个5。 然后看代码结构。每个解决方案都维护了5元和10元的数量,不需要记录20元,因为20元不会被用来找零。遍历账单时,根据不同的面值进行处理。比如,收到5元就直接增加计数;收到10元,必须有一个5元来找零;收到20元,优先用10+5,否则用三个5。 现在需要检查用户提供的代码是否有错误。比如引用1中的初始条件判断if(bills[0]!=5|| bills[1]==20),这可能有问题,因为如果账单长度为1,bills[1]会导致越界。所以正确的做法应该是在循环中处理每个账单,而不是预先检查前两个元素。其他引用中的代码可能更正确,比如引用2和3中的处理方式,没有预先检查,而是在循环中逐个处理。所以正确的做法应该是,逐个处理每个账单。对于每个顾客,根据他们付的钱进行相应的找零。例如,第一个顾客必须付5,否则返回false。但不需要在代码中预先检查第一个元素,因为当遍历到第一个元素时,如果是10或20,就会触发找零失败的条件。接下来,整合代码结构。正确的做法是初始化five和ten为0,然后遍历每个账单。对于每个账单:-如果是5元,five加1。-如果是10元,检查five是否大于0,是的话five减1,ten加1;否则返回false。-如果是20元,先检查是否有ten和five,有的话各减1;否则检查是否有三个five,有的话减3;否则返回false。这样处理可以覆盖所有情况。例如,引用5中的代码处理20元时,优先使用10+5,否则用三个5,这符合贪心策略。 然后,需要确保代码没有错误。比如,在引用4的Java代码中,处理20元时有条件判断,但可能有问题,比如是否同时满足ten>=1和five>=1。而C++的代码通常更直接,像引用2中的处理方式更简洁。 现在,把这些整合成一个C++的解决方案。需要注意的是,在遍历过程中,不需要处理20元的计数,因为20元不会用于找零。同时,必须处理每个顾客的情况,一旦无法找零就立即返回false,否则最后返回true。 最后,验证示例是否正确。例如,测试案例bills =[5,5,10,10,20],处理过程应该是: -第一个5,five=1-第二个5,five=2-第一个10,需要找5,five=1,ten=1-第二个10,需要找5,five=0,ten=2-20,需要找15。此时没有ten,但five=0,无法找零,返回false。所以整个结果应该是false,而根据代码逻辑,当处理最后一个20时,会检查ten和five,都没有,返回false。所以正确。另一个测试案例是bills =[5,5,5,10,20],处理过程:-前三个5,five=3-10,找5,five=2,ten=1-20,需要找15,优先用10+5,所以ten=0,five=1,此时five=1足够。返回true。所以代码逻辑正确。 综上所述,正确的C++实现应该按照上述逻辑编写,逐个处理账单,维护five和ten的计数,优先使用大面额找零。</think>### C++实现柠檬水找零算法解决方案 #### 问题分析 柠檬水找零问题要求正确找零每位顾客支付的5、10、20美元。贪心算法的核心是**优先使用大面额零钱**,例如收到20美元时优先用10+5的组合找零,而不是三个5美元[^1][^3]。 #### 实现步骤 1. **初始化计数器**:记录5美元和10美元的数量(20美元无法用于找零) 2. **遍历账单**: - 收到$5:直接存入 - 收到$10:必须用$5找零 - 收到$20:优先用$10+$5,否则用三个$5 3. **失败条件**:任何一步无法完成找零立即返回false #### 代码实现 ```cpp #include <vector> using namespace std; class Solution { public: bool lemonadeChange(vector<int>& bills) { int five = 0, ten = 0; for (int bill : bills) { if (bill == 5) { five++; } else if (bill == 10) { if (five == 0) return false; five--; ten++; } else { // 处理20美元 if (ten > 0 && five > 0) { // 优先用10+5 ten--; five--; } else if (five >= 3) { // 次选用三个5 five -= 3; } else { return false; } } } return true; } }; ``` #### 关键点说明 1. **贪心策略验证**:优先消耗$10可减少$5的占用,例如账单`[5,5,10,20]`时,用$10+$5找零比三个$5更优[^2][^4] 2. **时间复杂度**:$O(n)$,仅需一次遍历 3. **空间复杂度**:$O(1)$,仅用两个计数器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值