题目:
狒狒喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。
狒狒可以决定她吃香蕉的速度 K (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 K 根。如果这堆香蕉少于 K 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉,下一个小时才会开始吃另一堆的香蕉。
狒狒喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。
返回她可以在 H 小时内吃掉所有香蕉的最小速度 K(K 为整数)。
示例 :
输入: piles = [3,6,7,11], H = 8 输出: 4
思路:
最小速度应该首先取决于H,返回时长应该大于堆数,这样最起码能满足每一堆花一个小时解决。
先看H比堆数大多少,也就是H和piles.ength的差值,代表能余出来多少小时。在看这多出来的时间应该如何分配。
或者不用这么麻烦,将K从一到最大香蕉数做一个二分查找,再算出时间,算出在时间内最小的速度K就行了。
复杂度:
时间:查找是logn,共有m堆香蕉,总复杂度在(mlogn)
空间:O(1)
代码:
private int[] piles;
public int minEatingSpeed(int[] piles, int h) {
this.piles = piles;
// 获取最大速度, 由于一次最多只能吃一堆香蕉, 所以最大速度为最大一堆香蕉的数量
int maxSpeed = Integer.MIN_VALUE;
for(int pile : piles){
maxSpeed = Math.max(maxSpeed, pile);
}
// 左指针是最小速度, 右指针是最大速度
int left = 1, right = maxSpeed;
while (left < right){
int mid = left + (right - left) / 2;
if(getEattingHour(mid) > h){
// 当以 mid 速度吃完香蕉的时间 > h , 则提速要提升, left 指针右移
left = mid + 1;
}else{
// 当以 mid 速度吃完香蕉的时间 <= h , 则最低吃香蕉速度可能为 mid, 或者 比 mid 小 ,
// 所以, right = mid , 而不是 mid - 1
right = mid;
}
}
// 最终 left == right, 指向就是最小速度
return left;
}
// 计算以 speed 的速度吃完香蕉的时间
private int getEattingHour(int speed){
int hour = 0;
// 由于,每次最多吃一堆, 所以吃完香蕉的总时间需要 计算每堆香蕉吃完的时间
for(int pile : piles){
// 每堆香蕉吃完的时间 = 这一堆香蕉数/吃的速度, 结果向上取整
hour += (pile + speed - 1) / speed;
}
return hour;
}