【LeetCode刷题】NO.12

130 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一.题目

875. 爱吃香蕉的珂珂

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

珂珂可以决定她吃香蕉的速度 K (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉K根。如果这堆香蕉少于K根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。 珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。 返回她可以在 H 小时内吃掉所有香蕉的最小速度 KK 为整数)。 示例 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 <= 10^4
  • piles.length <= H <= 10^9
  • 1 <= piles[i] <= 10^9

二、思路分析:

这道题目乍一看觉得不是什么二分搜索题目,但是我们直到一般的题目利用暴力解法往往会超出时间限制。所以这道题我根据laluladong大佬的思路确定了这道题可以使用二分搜索的思路进行求解,大佬提供的思路要求我们提供Xtarget以及f(X)。二分搜索问题实际上是找到一个我们需要的自变量X,根据题目,需要找到珂珂吃香蕉的速度,所以我们就确定X就是吃香蕉的速度,因为题目中说明珂珂喜欢慢慢吃,那么说明时间越慢越好,故target = H。我们还需要直到f(X)关于X的变化,已知X越大时间就越快,所以确定f(X)是单调递减的函数。一般来说,求最值的过程就是利用二分搜索查找所需要的值的最左还是最右值。

我们先进行初始化leftright变量,最小速度为1,最大速度就是所有堆中最多的香蕉数,所以我们可以得出需要是左侧target搜索还是右侧target搜索,由题目得知X越小越好,所以我们需要利用左侧target搜索的框架进行求解。

image.png

三、代码:

/**
 * @param {number[]} piles
 * @param {number} h
 * @return {number}
 */
var minEatingSpeed = function(piles, h) {
    let left = 1;
    let right = Math.max(...piles);
    const f = (piles,x) =>{
        let hour = 0
        for(const pile of piles){
            hour += Math.ceil(pile/x)
        }
        return hour
    }
    while(left < right){
        let mid = Math.floor(left + (right - left)/2)
        if( f(piles,mid) == h){
            right = mid
        }else if(f(piles,mid) > h){
            //需要让f(x)的返回值小一些,由于f(x)单调递减,所以需要自变量往右侧增加
            left = mid + 1
        }else if(f(piles,mid) < h){
            //需要让f(x)的返回值大一些
            right = mid
        }
    }
    return left
};

四、总结:

我们在使用二分搜索求解问题的时候,一定要清楚在判断条件下leftright怎么变化,如果f(x)针对于原数组的情况下,我们只需要按照基本的框架思路来写就可以,但是如果f(x)不是原数组而是关于x自变量变化的函数时,我们就需要直到f(x)是单调递增还是单调递减的函数,然后在判断条件的时候对left以及right的情况做出相应的更改。