题目:
珂珂喜欢吃香蕉。这里有
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
思路:
这个问题是一个典型的二分查找问题,需要找到能够满足条件的最小的速度值。珂珂需要在警卫回来前吃掉所有的香蕉,所以我们需要找到一个速度,使得吃掉所有香蕉的时间不超过给定的
h
小时。解决这个问题的步骤如下:
确定搜索范围:最小的速度是1(每小时至少吃一个香蕉),最大的速度是所有香蕉堆中香蕉数量最多的那一堆(最坏的情况是只有一堆香蕉,且这堆香蕉的数量就是最大速度)。
二分查找:在确定的搜索范围内,使用二分查找来找到最小的速度。对于每一个中间速度,计算吃掉所有香蕉所需的时间。
计算时间:对于每个速度,遍历每一堆香蕉,计算吃掉每一堆所需的时间,并将这些时间累加起来。计算每一堆香蕉所需的时间时,如果香蕉堆的数量能够被速度整除,那么所需时间就是香蕉堆数量除以速度;如果不能整除,那么需要向上取整,因为即使最后一分钟没有吃完整个香蕉堆,也会算作一分钟。
调整搜索范围:如果计算出的总时间小于等于
h
,说明当前速度可能偏大或者正好是我们要找的速度,因此需要调整搜索范围,缩小到当前速度及其以下的部分;如果计算出的总时间大于h
,说明当前速度偏小,需要调整搜索范围到当前速度以上。找到最小速度:重复二分查找过程,直到找到最小的速度,使得吃掉所有香蕉的时间不超过
h
小时。返回结果:最后,返回找到的最小速度
k
。
代码:
C++
class Solution { public: int minEatingSpeed(vector<int>& piles, int h) {
定义了一个名为
Solution
的类,其中包含一个公共成员函数minEatingSpeed
,它接受一个整数向量piles
(代表香蕉堆的大小)和一个整数h
(代表给定的小时数)。int low = 1; int high = 0;
初始化二分查找的最低速度
low
为1(因为至少每分钟吃一个香蕉),最高速度high
初始为0,后面会根据香蕉堆的大小更新这个值。for (int pile : piles) { high = max(high, pile); }
遍历所有的香蕉堆,将
high
更新为当前香蕉堆大小和high
中的较大值。这样,high
最后会包含最大的香蕉堆大小,即在最坏情况下,最大速度就是最大的香蕉堆大小。int k = high;
初始化结果变量
k
为high
,即当前假设的最大速度。while (low < high) {
开始一个循环,只要
low
小于high
,就继续二分查找。int speed = (high - low) / 2 + low;
计算当前的速度,即
low
和high
之间的中间值。long time = getTime(piles, speed);
调用
getTime
函数来计算以当前速度吃完所有香蕉堆需要的时间。if (time <= h) { k = speed; high = speed; } else { low = speed + 1; }
如果计算出的时间小于等于给定的时间
h
,说明当前速度可能是可行的最小速度。将k
更新为当前速度,并将high
设置为当前速度,这样在下一次循环中查找的范围就会缩小到当前速度及其以下。如果计算出的时间大于给定的时间h
,说明当前速度太小,需要增加速度。因此,将low
设置为当前速度加一,这样在下一次循环中查找的范围就会是当前速度以上。} return k; }
循环结束,返回最终计算出的最小速度k。
long getTime(const vector<int>& piles, int speed) { long time = 0; for (int pile : piles) { int curTime = (pile + speed - 1) / speed; time += curTime; } return time; } };
定义了一个名为
getTime
的辅助函数,它接受一个整数向量piles
和一个整数speed
,返回以当前速度吃完所有香蕉堆需要的时间。遍历每一堆香蕉,计算吃完每一堆需要的时间,并累加到总时间time
中。这里(pile + speed - 1) / speed
确保了即使最后一分钟没有吃完整个香蕉堆,也会算作一分钟。函数结束,返回计算出的总时间。
Python:
import math class Solution: def minEatingSpeed(self, piles: List[int], h: int) -> int: low, high = 1, max(piles) while low < high: mid = (low + high) // 2 if self.canFinish(piles, mid, h): high = mid else: low = mid + 1 return low def canFinish(self, piles: List[int], speed: int, h: int) -> bool: time = 0 for pile in piles: time += math.ceil(pile / speed) return time <= h
对代码的详细解释:
导入
math
模块,以便使用math.ceil
函数进行向上取整。定义一个名为Solution
的类,用于包含解决问题的方法。定义一个名为minEatingSpeed
的方法,它接受一个整数列表piles
(代表香蕉堆的大小)和一个整数h
(代表给定的小时数),并返回一个整数(最小速度)。初始化二分查找的最低速度low
为1,最高速度high
为香蕉堆中的最大值,这是可能的最大速度。开始一个循环,只要low
小于high
,就继续二分查找。计算中间速度mid
,这是当前搜索范围的中间值。调用canFinish
方法来检查以中间速度mid
是否能在h
小时内吃完所有的香蕉堆。如果可以吃完,说明当前速度可能偏大或者正好是我们要找的速度,因此将high
设置为mid
,缩小搜索范围到中间速度及其以下。如果无法吃完,说明当前速度偏小,需要增加速度,因此将low
设置为mid + 1
,缩小搜索范围到中间速度以上。循环结束后,返回low
,这是珂珂可以在h
小时内吃掉所有香蕉的最小速度。定义一个名为canFinish
的辅助方法,它接受一个整数列表piles
,一个整数speed
和一个整数h
,返回一个布尔值,表示以当前速度是否能在h
小时内吃完所有的香蕉堆。初始化总时间time
为0。遍历每一堆香蕉,计算吃完每一堆需要的时间,并累加到总时间time
中。使用math.ceil
确保即使最后一分钟没有吃完整个香蕉堆,也会算作一分钟。返回一个布尔值,表示总时间是否小于等于给定的时间h
。
这是我对这一题的一些看法, 如果大家觉得我的想法还不错的话,留下一个小小的赞波!!!