題目連結: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;
}
};