柠檬水找零(贪心/分类/模拟)

98 阅读2分钟

 该题我的第一思路是模拟该题找钱的一个过程,首先我们面对收到5元的话,我们就直接收下,再使用嵌套循环来遍历bills的同时我们从我们拥有的最大面额的钱开始遍历,看看能不能找给顾客(因为在该题中5元是比较珍贵的,毕竟需要使用 5 美元的找零场景会比需要使用 10 美元的找零场景多,我们需要尽可能保留 5 美元的钞票),同时对我们的钱数和要找的钱数进行更新,直到完整找给顾客钱

下面就是代码实现

class Solution {
public://模拟
  bool lemonadeChange(vector<int>& bills) {
    if (bills[0] != 5)
    {
        return false;
    }
    int mymoney[25] = { 0 };
    int i = 0, t = 0;
    while (bills[i] == 5)
    {
        mymoney[5]++;//5美金的数量
        i++;
    }
    for (int j = i; j < bills.size(); j++)
    {
        int to_cust = bills[j] - 5;//需要找给顾客的钱
        for (int z = 10; z > 0; z -= 5)//从我最大的钱开始看能不能找
        {
            int need = to_cust / z;//这种钱需要多少张
            if (need && mymoney[z] >= need)//需要这种钱且我有
            {
                to_cust -= (z * need);//需要找的钱减少
                mymoney[z] -= need;
                //我的钱增加了和减少了
            }
            if (to_cust == 0)
            {
                t++;
                break;
            }
        }
        if (to_cust != 0)
        {
            return false;
        }
        mymoney[bills[j]]++;//我收到顾客的钱
    }
    if (t == (bills.size()-(i)))
    {
        return true;
    }
    else
    {
        return false;
    }
}
};

 下面这个思路是在LeetCode上面的官方题解思路:直接分类讨论

由于顾客只可能给你三个面值的钞票,而且我们一开始没有任何钞票,因此我们拥有的钞票面值只可能是 5 美元,10 美元和 20 美元三种。基于此,我们可以进行如下的分类讨论。

  • 5 美元,由于柠檬水的价格也为 5 美元,因此我们直接收下即可。
  • 10 美元,我们需要找回 55美元,如果没有 5 美元面值的钞票,则无法正确找零。
  • 20 美元,我们需要找回 15 美元,此时有两种组合方式,一种是一张 10 美元和 5 美元的钞票,一种是 3张 5 美元的钞票,如果两种组合方式都没有,则无法正确找零。当可以正确找零时,两种找零的方式中我们更倾向于第一种,即如果存在 5美元和 10 美元,我们就按第一种方式找零,否则按第二种方式找零,因为需要使用 5 美元的找零场景会比需要使用 10 美元的找零场景多,我们需要尽可能保留 5美元的钞票。

基于此,我们维护两个变量 five 和 ten 表示当前手中拥有的 5美元和 10 美元钞票的张数,从前往后遍历数组分类讨论即可。

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five=0,ten=0;
        for(int i=0;i<bills.size();i++)
        {
            if(bills[i]==5)
            {
                five++;
            }
            else if(bills[i]==10)
            {
                if(five==0)//注意检查钱数够不够
                {
                    return false;
                }
                five--;
                ten++;
            }
            else if(bills[i]==20)
            {
                if(ten>0&&five>0)//优先用10元和5元的组合
                {
                    ten--;
                    five--;
                }
                else if(five>=3)
                {
                    five-=3;
                }
                else 
                {
                    return false;
                }
            }
        }
        return true;
    }
};