【LeetCode 875】爱吃香蕉的珂珂

题目描述

原题链接: LeetCode.875 爱吃香蕉的珂珂

解题思路

  • 如果当前堆剩余香蕉数量小于每小时吃的数量, 吃完当前堆就会休息不会去吃下一堆的香蕉, 所以吃完一堆所需时间就是堆的香蕉数量除以速度的向上取整值:\(\lceil {piles[i]/speed} \rceil\)
  • 首先确定答案所处的范围, 速度最小值可以是1, 最大值很明显没必要超过所有堆中香蕉数量的最大值;
  • 如果假定的速度speed能在不超过指定H小时内吃完所有香蕉, 任意大于speed的速度也肯定可以在H小时内吃完, 否则就该尝试更小的speed能否在指定时间内吃完;
  • 二分判断函数逻辑就是给定speed能否在不超过H小时内吃完所有香蕉;
  • 在给定范围内不断二分尝试, 找到最小符合需求的速度即可;
  • 时间复杂度很明显就是O(nlogMAX);
  • 对于二分范围, 可以粗略定一个较大的, 对复杂度不会有多大影响, 追求极致性能的可以再细致的缩小边界, 但是务必注意不要遗漏正确的答案区域导致出错;

解题代码

  • 朴素二分法代码:

      /**
       * 典型二分查找的题目
       * 执行用时: 6 ms , 在所有 Java 提交中击败了 99.30% 的用户
       * 内存消耗: 14.75 MB , 在所有 Java 提交中击败了 14.75% 的用户
       */
      public int minEatingSpeed(int[] piles, int h) {
          int left = 1, right = 0;
          for (int p : piles) {
              right = Math.max(p, right);
          }
          int ans = left;
          while (left <= right) {
              int mid = left + ((right - left) >> 1);
              if (eatAllWithinH(piles, h, mid)) {
                  ans = mid;
                  right = mid - 1;
              }
              else {
                  left = mid + 1;
              }
          }
          return ans;
      }
    
      private boolean eatAllWithinH(int[] piles, int h, int speed) {
          int cnt = 0;
          for (int p : piles) {
              // 吃掉一堆的小时数是piles[i]/speed向上取整的值
              cnt += (p - 1) / speed + 1;
              if (cnt > h) {
                  return false;
              }
          }
          return true;
      }
    
  • 更细致的二分范围代码:

      /**
       * 对复杂度没影响, 但是能稍微优化些的二分范围值
       * 执行用时: 1 ms , 在所有 Java 提交中击败了 99.69% 的用户
       * 内存消耗: 43.99 MB , 在所有 Java 提交中击败了 64.63% 的用户
       */
      public int minEatingSpeed(int[] piles, int h) {
          long sum = 0;
          for (int p : piles) {
              sum += p;
          }
          int left = (int) ((sum - 1) / h) + 1;
          int right = (int) (sum / (h - piles.length + 1)) + 1;
          int ans = left;
          while (left <= right) {
              int mid = left + ((right - left) >> 1);
              if (eatAllWithinH(piles, h, mid)) {
                  ans = mid;
                  right = mid - 1;
              }
              else {
                  left = mid + 1;
              }
          }
          return ans;
      }
    

posted on 2024-05-13 20:48  真不如烂笔头  阅读(9)  评论(0编辑  收藏  举报

导航