Lemonade Change
題目描述:你在賣每杯 5 元的檸檬水,顧客只會付 5 元、10 元或 20 元。初始時你沒有任何零錢,判斷能否給每位顧客正確找零。
解題思路:
這是一道直觀的貪心模擬題。我們只需要追蹤手頭的 5 元和 10 元鈔票數量(20 元不需要追蹤,因為 20 元鈔票無法用於找零)。
三種情況分析:
-
顧客付 5 元:不需要找零,收入 five++。
-
顧客付 10 元:需要找回 5 元。若 five > 0,則 five--,ten++;否則回傳 false。
-
顧客付 20 元:需要找回 15 元。優先用 1 張 10 元 + 1 張 5 元(貪心選擇:保留更多 5 元,因為 5 元用途最廣),若不夠則嘗試 3 張 5 元;兩者都不夠則回傳 false。
為何優先用 10 元找零:10 元鈔票只能用於找零 20 元的情況,而 5 元鈔票可用於找零 10 元和 20 元兩種情況。因此 5 元更珍貴,應儘量保留。
範例說明:
bills = [5, 5, 5, 10, 20]
5 → five = 1
5 → five = 2
5 → five = 3
10 → five = 2, ten = 1(找回 1 個 5 元)
20 → ten = 0, five = 1(找回 1 個 10 + 1 個 5)
結果:true
方法一:追蹤所有面額(通用化)
用一個 map 記錄各面額鈔票數量,找零時從大面額往小面額貪心扣除。這種方法更具通用性,可以擴展至任意面額組合,但對本題來說過於繁瑣。
map<int, int> cash;
for (int bill : bills) {
cash[bill]++;
int change = bill - 5;
for (auto it = cash.rbegin(); it != cash.rend() && change > 0; it++) {
int use = min(it->second, change / it->first);
it->second -= use;
change -= use * it->first;
}
if (change != 0) return false;
}
return true;
時間複雜度 O(n × k),k 為面額種類數。
方法二:只追蹤 5 元鈔票(特化觀察)
注意到 10 元鈔票只在找零 20 元時才用得到,且用 10 元找零一定優先於用 5 元。可以進一步觀察:20 元找零時必然消耗一張 5 元;因此實際上只需記錄 5 元和 10 元的數量,等同於目前的標準解法。這不是進一步的簡化,而是驗證了標準解法已是最精簡的形式。
方法三:模擬計算總量
直接計算任意時刻手頭的零錢總額(只計 5 元和 10 元),若任一時刻無法湊出找零金額則失敗。但這種方法難以判斷具體面額是否夠用,仍需分別追蹤面額,等同於標準解法。