【算法35天:Day35】第八章贪心算法 柠檬水找零(860)

129 阅读1分钟

题目一:

image.png

解法一:(模拟)

解题思路:这个解法是自己做出来的,可能就是常规暴力解法吧。

  • 先声明一个priceNum数组,记录5美元以及10美元的数量,索引0位置为5美元数量,索引1位置为10美元数量
  • 当遇到5美元时,priceNum[0]++
  • 当遇到10美元时,priceNum[1]++,同时priceNum[0]--,判断priceNum[0]是否小于零,如果小于零,则表示无法找零
  • 当遇到20美元时,先判断priceNum[1]是否大于0,因为大于零,表示有10美元,优先找10美元,再priceNum[0]--,判断priceNum[0]是否小于零,如果小于零,则表示无法找零
  • 如果priceNum[1]不大于0,则priceNum[0] -= 3,找3个五美元,判断priceNum[0]是否小于零,如果小于零,则表示无法找零
  • 最后返回true

完整代码如下:

var lemonadeChange = function(bills) {
    let priceNum = [0, 0]
    for (let i = 0; i < bills.length; i++) {
        if (bills[i] == 5) {
            priceNum[0]++
        } else if (bills[i] == 10) {
            priceNum[1]++
            priceNum[0]--
            if (priceNum[0] < 0) {
                return false
            }
        } else {
            if (priceNum[1] > 0) {
                priceNum[1]--
                priceNum[0]--
                if (priceNum[0] < 0) {
                    return false
                }
            } else {
                priceNum[0] -= 3
                if (priceNum[0] < 0) {
                    return false
                }
            }
        }
    }
    return true
};

解法二:(贪心算法:代码随想录)

思路

这是前几天的leetcode每日一题,感觉不错,给大家讲一下。

这道题目刚一看,可能会有点懵,这要怎么找零才能保证完整全部账单的找零呢?

但仔细一琢磨就会发现,可供我们做判断的空间非常少!

只需要维护三种金额的数量,5,10和20。

有如下三种情况:

  • 情况一:账单是5,直接收下。
  • 情况二:账单是10,消耗一个5,增加一个10
  • 情况三:账单是20,优先消耗一个10和一个5,如果不够,再消耗三个5

此时大家就发现 情况一,情况二,都是固定策略,都不用我们来做分析了,而唯一不确定的其实在情况三。

而情况三逻辑也不复杂甚至感觉纯模拟就可以了,其实情况三这里是有贪心的。

账单是20的情况,为什么要优先消耗一个10和一个5呢?

因为美元10只能给账单20找零,而美元5可以给账单10和账单20找零,美元5更万能!

所以局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。

局部最优可以推出全局最优,并找不出反例,那么就试试贪心算法!

var lemonadeChange = function(bills) {
    let fiveCount = 0
    let tenCount = 0

    for(let i = 0; i < bills.length; i++) {
        let bill = bills[i]
        // 情况一
        if(bill === 5) {
            fiveCount += 1
        } else if (bill === 10) {
            // 情况二
            if(fiveCount > 0) {
                fiveCount -=1
                tenCount += 1
            } else {
                return false
            }
        } else {
            // 情况三
            if(tenCount > 0 && fiveCount > 0) {
                tenCount -= 1
                fiveCount -= 1 
            } else if(fiveCount >= 3) {
                fiveCount -= 3
            } else {
                return false
            }
        } 
    }
    return true
};

总结

咋眼一看好像很复杂,分析清楚之后,会发现逻辑其实非常固定。

这道题目可以告诉大家,遇到感觉没有思路的题目,可以静下心来把能遇到的情况分析一下,只要分析到具体情况了,一下子就豁然开朗了。

如果一直陷入想从整体上寻找找零方案,就会把自己陷进去,各种情况一交叉,只会越想越复杂了。