二分查找(小于等于指定数的最小值):求解《875. 爱吃香蕉的珂珂》

2022-06-07 14:12:36
二分查找(小于等于指定数的最小值),求解《875. 爱吃香蕉的珂珂》

例题

875. 爱吃香蕉的珂珂

珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。
珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。
珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。
返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。
示例 1:
输入:piles = [3,6,7,11], h = 8
输出:4

答案

二分查找

var minEatingSpeed = function(piles, h) {
  const n = piles.length
  let max = 1, sum = 0
  for (let i = 0; i < n; i++) {
    sum += piles[i]
    if (piles[i] > max) max = piles[i]
  }
  let l = sum / h | 0, r = max
  while (l <= r) {
    const m = l + r >>> 1
    let time = 0
    for (let i = 0; i < n; i++) {
      time += Math.ceil(piles[i] / m)
    }
    if (time <= h) r = m - 1
    else l = m + 1
  }
  return l
};
function minEatingSpeed(piles: number[], h: number): number {
  const n = piles.length
  let sum = 0, max = 1
  for (let i = 0; i < n; i++) {
    sum += piles[i]
    if (piles[i] > max) max = piles[i]
  }
  let l = sum / h | 0, r = max
  while (l <= r) {
    const m = l + r >>> 1
    let time = 0
    for (let i = 0; i < n; i++) {
      time += Math.trunc((piles[i] - 1) / m) + 1
    }
    if (time <= h) r = m - 1
    else l = m + 1 
  }
  return l
};
class Solution {
  function minEatingSpeed($piles, $h) {
    $sum = 0;
    $max = 1;
    foreach ($piles as $pile) {
      $sum += $pile;
      if ($pile > $max) $max = $pile;
    }
    $l = $sum / $h | 0;
    $r = $max;
    while ($l <= $r) {
      $m = $l + $r >> 1;
      $time = 0;
      if ($m == 0) return 1;
      foreach($piles as $pile) {
        $time += ceil($pile / $m);
      }
      if ($time <= $h) $r = $m - 1;
      else $l = $m + 1;
    }
    return $l;
  }
}
func minEatingSpeed(piles []int, h int) int {
  max := 1
  for _, pile := range piles {
    if pile > max {
      max = pile
    }
  }
  return 1 + sort.Search(max, func(m int) bool {
    m++
    time := 0
    for _, pile := range piles {
      time += (pile - 1) / m + 1
    }
    return time <= h
  })
}
class Solution {
  public int minEatingSpeed(int[] piles, int h) {
    long sum = 0, max = 1;
    for (int pile : piles) {
      sum += pile;
      if (pile > max) max = pile;
    }
    long l = sum / h;
    long r = max;
    while (l <= r) {
      long m = l + r >>> 1, time = 0;
      if (m == 0) return 1;
      for (int pile : piles) {
        time += (pile - 1) / m + 1;
      }
      if (time <= h) r = m - 1;
      else l = m + 1;
    }
    return (int)l;
  }
}
class Solution:
  def minEatingSpeed(self, piles: List[int], h: int) -> int:
    l, r = sum(piles) // h, max(piles)
    while l <= r:
      m, time = l + r >> 1, 0
      if m == 0: return 1
      for _, pile in enumerate(piles):
        time += (pile - 1) // m + 1
      if time <= h: r = m - 1
      else: l = m + 1
    return l

二分查找:求解《33. 搜索旋转排序数组》和《153. 寻找旋转排序数组中的最小值》
二分查找,求解《33. 搜索旋转排序数组》
排序,二分查找:求解《436. 寻找右区间》
排序,二分查找(Python 的 bisect.bisect_left 和 Golang 的 sort.Search),求解《436. 寻找右区间》
二分查找:求解《668. 乘法表中第k小的数》
二分查找,求解《668. 乘法表中第k小的数》