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;
}
}