【3.2】贪心算法-解柠檬水找零

一、题目

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

示例 1:
输入: [ 5 , 5 , 5 , 10 , 20 ]
输出: true
解释:
3 位顾客那里,我们按顺序收取 3 5 美元的钞票。
4 位顾客那里,我们收取一张 1 0 美元的钞票,并返还 5 美元。
5 位顾客那里,我们找还一张 1 0 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零,所以我们输出 tru e
示例 2
输入 [ 5 , 5 , 1 0 ]
输出 true
示例 3
输入 [ 1 0 , 1 0 ]
输出 false
示例 4
输入 [ 5 , 5 , 1 0 , 1 0 , 2 0 ]
输出 false
解释
2 位顾客那里,我们按顺序收取 2 5 美元的钞票。
对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。
对 于 最 后 一 位 顾 客 , 我 们 无 法 退 回 15 美 元 , 因 为 我 们 现 在 只 有 两 张 10 美 元 的钞票。 由于不是每位顾客都得到了正确的找零,所以答案是 false
提示:
1)0  <=  bills.length < = 10000
2)bills[ i ] 不是 5 就是 10 或是 20

二、求解思路

        这道题目反映了日常生活中常见的一种情景。我们的目标是为每一位顾客提供找零服务。如果能确保每位顾客都能得到足够的找零,那么我们返回 `true`;反之,如果任何一位顾客无法得到足够的找零,我们则返回 `false`。

        顾客使用的纸币仅限于5元、10元和20元三种。我们需要关注的是5元和10元的纸币数量,因为20元纸币无法用于找零。

具体操作如下:
        当顾客支付5元时,我们将5元纸币的数量增加1。
        当顾客支付10元时,我们需要找给他一张5元纸币,因此5元纸币的数量减少1。在此之后,我们检查5元纸币的数量,如果数量变为负数,表明我们无法完成找零,此时应立即返回 `false`。
        当顾客支付20元时,根据常规做法,我们应优先使用10元纸币进行找零,然后再使用一张5元纸币。如果没有10元纸币,我们则使用三张5元纸币进行找零。完成找零后,我们同样需要检查5元纸币的数量,如果数量小于0,则表明找零失败,应返回 `false`。

三、代码实现

        下面的代码实现了一个贪心算法。贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。

在这个问题中,代码遵循了以下贪心策略:

  1. 优先使用10元找零:当顾客支付20元时,如果有10元的零钱,优先使用10元找零,然后再使用5元找零。这是因为10元纸币在找零时比5元纸币更“珍贵”,因为它可以一次性找零10元,而5元纸币需要两张才能达到同样的效果。

  2. 尽量保留5元纸币:5元纸币是最基本的找零单位,因此在找零时尽量保留5元纸币,以备后续可能需要用更多的5元纸币找零的情况。

        代码通过遍历顾客支付的账单数组,根据每一步的支付金额来更新店员手中的5元和10元纸币的数量,并在每一步检查5元纸币的数量是否足够找零。如果某一步5元纸币的数量变为负数,说明无法完成找零,算法返回false。如果遍历结束时5元纸币的数量始终非负,则说明可以完成所有找零,算法返回true

        这种策略确保了在每一步都做出了当前看起来最优的选择,即使用了贪心算法的思想。

#include 
#include 

bool lemonadeChange(std::vector& 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 { // bill == 20
            if (ten > 0 && five > 0) {
                ten--;
                five--;
            } else if (five >= 3) {
                five -= 3;
            } else {
                return false;
            }
        }
    }
    return true;
}

int main() {
    std::vector bills = {5, 5, 5, 10, 20};
    if (lemonadeChange(bills)) {
        std::cout << "true" << std::endl;
    } else {
        std::cout << "false" << std::endl;
    }
    return 0;
}

        在进行找零操作时,我们并未事先检查5元纸币的数量,而是在完成找零后才评估5元纸币的余量是充足还是不足。当然,我们也可以在每次找零前预先判断5元纸币的数量,但这会略显繁琐,因为除了顾客支付5元的情况外,其他情况下都需要进行这一额外的检查步骤。

你可能感兴趣的:(贪心算法,算法,c++)