Mkdir700's Note

Mkdir700's Note

【LC】875. 爱吃香蕉的珂珂

820
2022-02-26

珂珂喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。

珂珂可以决定她吃香蕉的速度 K (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 K 根。如果这堆香蕉少于 K 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。  

珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。

返回她可以在 H 小时内吃掉所有香蕉的最小速度 K(K 为整数)。

示例 1:

输入: piles = [3,6,7,11], H = 8
输出: 4
示例 2:

输入: piles = [30,11,23,4,20], H = 5
输出: 30
示例 3:

输入: piles = [30,11,23,4,20], H = 6
输出: 23
 

提示:

1 <= piles.length <= 104
piles.length <= H <= 10
9
1 <= piles[i] <= 10^9

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/koko-eating-bananas
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


痛点分析

这道题使用二分查找的基本思路是没有问题的。
其难点在于确定二分查找的范围,如果无脑用[1, max(piles)]就出现超时的情况。

  • 使用piles中最小元素(每小时最小消耗速度),计算得出总耗时。
    • 总耗时大于h,则说明花费的时间太长了需要加快速度,所以,此时可确定二叉查找的范围为[max(piles), max(piles)]
    • 否则呢,说明花费的时间太短即速度太快,需要减缓速度,所以,可确定二叉查找范围为[1, min(piles)]

0x01

class Solution:
    def minEatingSpeed(self, piles: List[int], h: int) -> int:        
        def helper(k):
            s = 0
            for p in piles:
                # 优雅写法:s += (p + k - 1) // k
                if p <= k:
                    s += 1
                else:
                    s += math.ceil(p / k)
            return s
        
        # 关键在于二叉搜索范围的确定
        minn, maxn = min(piles), max(piles)
        if helper(minn) > h:
            # 最小速度所消耗的时间大于H,太慢了,需要扩大消耗速度
            left, right = minn, maxn
        else:
            left, right = 1, minn
        
        while left < right:
            k = (left + right) >> 1
            if helper(k) > h:
                # 耗时太快,则加快速度
                left = k + 1
            else:
                # 耗时太短,则减慢速度
                right = k                
        return left