【LeetCode】每日一题 剑指 Offer II 073. 狒狒吃香蕉

163 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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;
}

如果你对这道题目还有疑问的话,可以在评论区进行留言;