持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情
剑指 Offer II 073. 狒狒吃香蕉
狒狒喜欢吃香蕉。这里有 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 <= 109
1 <= piles[i] <= 109
解题思路
每小时最多吃一堆香蕉,如果吃不下的话留到下一小时再吃;如果吃完了这一堆还有胃口,也只会等到下一小时才会吃下一堆。在这个条件下,让我们确定珂珂吃香蕉的最小速度(根/小时)
现在求的是最小速度,本质上是在一个范围内求目标值的左侧边界
很明显珂珂吃香蕉的速度最小为1,最大速度是piles数组中元素的最大值,因为每小时最多吃一堆香蕉
在最小速度和最大速度这个排序区间内求在 H 小时内吃掉所有香蕉的最小速度 K
就是用二分查找来搜索目标值的左侧边界
代码实现
/**
* @param {number[]} piles
* @param {number} h
* @return {number}
*/
var minEatingSpeed = function (piles, h) {
// 左闭右开区间
let left = 1,
right = Math.max(...piles) + 1;
while (left < right) {
let mid = left + ((right - left) >> 1);
if (canFinish(piles, mid, h)) {
// 因为是左闭右开区间 所以这里right = mid
// 搜索左侧边界,则需要收缩右侧边界
right = mid;
} else {
left = mid + 1;
}
}
return left;
};
// 吃完n根香蕉以speed的速度需要多少小时
function timeOf(n, speed) {
return Math.floor(n / speed) + (n % speed > 0);
}
// piles堆香蕉以speed的速度能否在h小时内吃完
function canFinish(piles, speed, h) {
let time = 0;
for (let a of piles) {
time += timeOf(a, speed);
}
return time <= h;
}
如果你对这道题目还有疑问的话,可以在评论区进行留言;