欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

875. 爱吃香蕉的珂珂(二分查找)

程序员文章站 2024-03-16 09:14:34
...

二分搜索只能用来查找元素吗?
参考下面这篇文章:二分搜索只能查找元素么?

当问题是在一个值有序的空间域中,获取一个满足条件的值,我们都可以考虑使用二分查找的方法,进行剪治去做,每次排除一半的搜索空间。

package com.heu.wsq.leetcode.binarysearch;

/**
 * 875. 爱吃香蕉的珂珂
 * @author wsq
 * @date 2021/4/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
 *
 * 链接:https://leetcode-cn.com/problems/koko-eating-bananas
 */
public class MinEatingSpeed {
    /**
     * 二分查找的场景题,不像是之前给了你一个有序数组,直接去寻找某个数,该题在二分查找之上增加了一层场景,
     * 让我们一眼看过去不是二分查找。
     * 下面的思想真是要去学习,把问题进行直观的分析,题目要求最小的速度完成,那么最小的速度可以是多少呢? 它的范围是多少?
     *
     * 
     * 那么我们先抛开二分查找技巧,想想如何暴力解决这个问题呢?
     * 首先,算法要求的是「H小时内吃完香蕉的最小速度」,我们不妨称为speed,请问speed最大可能为多少,最少可能为多少呢?
     * 显然最少为 1,最大为max(piles),因为一小时最多只能吃一堆香蕉。
     * 那么暴力解法就很简单了,只要从 1 开始穷举到max(piles),一旦发现发现某个值可以在H小时内吃完所有香蕉,这个值就是最小速度:
     * @param piles
     * @param h
     * @return
     */
    public int minEatingSpeed(int[] piles, int h) {
        if (piles == null || piles.length == 0){
            return 0;
        }
        if(piles.length > h){
            return -1;
        }
        int left = 1;
        int right = getMaxSpeed(piles);
        // 使用二分查找搜索满足条件的最小速度
        while(left <= right){
            int mid = (left + right) >> 1;

            boolean flag = canFinsh(piles, mid, h);
            if(flag){
                right = mid - 1;
            }else{
                left = mid + 1;
            }
        }
        return left;
    }

    private int getMaxSpeed(int[] piles){
        int maxSpeed = 0;
        for(int s: piles){
            maxSpeed = Math.max(maxSpeed, s);
        }
        return maxSpeed;
    }

    private boolean canFinsh(int[] piles, int speed, int h){
        for(int pile: piles){
            int tmpH = getHour(pile, speed);
            if(tmpH > h){
                return false;
            }
            h -= tmpH;
        }
        return true;
    }

    private int getHour(int pile, int speed){
        return (pile + speed - 1) / speed;
    }
}