LeetCode860. 檸檬水找零

Tomorrowland_D發表於2024-07-24

題目連結:https://leetcode.cn/problems/lemonade-change/description/

題目敘述:

在檸檬水攤上,每一杯檸檬水的售價為 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 <= 10^5
bills[i] 不是 5 就是 10 或是 20

思路:

採用貪心的思想:

這道題目剛一看,可能會有點懵,這要怎麼找零才能保證完成全部賬單的找零呢?

但仔細一琢磨就會發現,可供我們做判斷的空間非常少!

只需要維護三種金額的數量,5,10和20。

有如下三種情況:

情況一:賬單是5,直接收下。
情況二:賬單是10,消耗一個5,增加一個10
情況三:賬單是20,優先消耗一個10和一個5,如果不夠,再消耗三個5
此時大家就發現 情況一,情況二,都是固定策略,都不用我們來做分析了,而唯一不確定的其實在情況三。

而情況三邏輯也不復雜甚至感覺純模擬就可以了,其實情況三這裡是有貪心的。

賬單是20的情況,為什麼要優先消耗一個10和一個5呢?

因為美元10只能給賬單20找零,而美元5可以給賬單10和賬單20找零,美元5更萬能!

所以區域性最優:遇到賬單20,優先消耗美元10,完成本次找零。全域性最優:完成全部賬單的找零。

區域性最優可以推出全域性最優,並找不出反例,那麼就試試貪心演算法!

思路學習:https://programmercarl.com/0860.%E6%9F%A0%E6%AA%AC%E6%B0%B4%E6%89%BE%E9%9B%B6.html#%E6%80%9D%E8%B7%AF

C++程式碼示例

```cpp
class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five=0,ten=0;
        for(auto bill:bills){
            //五塊就直接收下
            if(bill==5) five++;
            //十塊,就看有沒有五塊的能找零,沒有就直接返回false
            else if(bill==10){
                if(five>=1) five--,ten++;
                else return false;
            }
            //二十塊,優先消耗一張10快,一張5塊。如果沒有,就看有沒有三張5塊的。
            //如果還是沒有,就返回false
            else if(bill==20){
                if(ten>=1&&five>=1){
                    five--;ten--;
                }
                else if(five>=3) five-=3;
                else return false;
            }
        }
        return true;
    }
};

相關文章