875. 爱吃香蕉的珂珂
爱吃香蕉的珂珂
珂珂喜欢吃香蕉。这里有 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
思路分析:
- 问题模型:
- 每一堆香蕉
piles[i]
,珂珂每小时吃k
根香蕉。 - 如果某堆香蕉数目小于
k
,珂珂会在一个小时内吃完这一堆。 - 我们需要找到最小的
k
,使得珂珂能够在h
小时内吃掉所有香蕉。
- 每一堆香蕉
- 计算吃香蕉所需的时间:
- 对于每一堆香蕉
piles[i]
,珂珂需要的时间是ceil(piles[i] / k)
,即香蕉数除以速度k
,向上取整。可以通过(piles[i] + k - 1) / k
来实现向上取整。 - 总时间是所有堆所需时间的总和,我们需要确保这个总时间小于等于
h
。
- 对于每一堆香蕉
- 二分查找:
- 速度
k
的最小值为 1,最大值为所有香蕉堆中最大的一堆max(piles)
。因为如果k
超过某堆香蕉的数量,珂珂每小时最多只吃一次。 - 我们可以对速度
k
进行二分查找,判断在给定的速度下是否可以在h
小时内吃掉所有香蕉。
- 速度
算法步骤:
- 设置二分查找的范围:最小值为
1
,最大值为max(piles)
。 - 使用
mid
作为当前的速度,计算所有堆香蕉的总吃完时间。 - 如果总时间小于等于
h
,说明当前速度可能是一个有效的解,尝试减小速度(即right = mid - 1
)。 - 如果总时间大于
h
,说明当前速度太小,需要增加速度(即left = mid + 1
)。 - 最终返回找到的最小速度
k
。
public class Solution {
public int minEatingSpeed(int[] piles, int h) {
int left = 1, right = 0;
// 找到香蕉堆中最大的堆
for (int pile : piles) {
right = Math.max(right, pile);
}
// 二分查找最小的速度 k
while (left <= right) {
int mid = left + (right - left) / 2;
if (canFinish(piles, mid, h)) {
right = mid - 1; // 如果能在 h 小时内吃完,则尝试减小速度
} else {
left = mid + 1; // 否则增加速度
}
}
return left;
}
// 判断在速度 k 下,是否可以在 h 小时内吃掉所有香蕉
private boolean canFinish(int[] piles, int k, int h) {
int hoursNeeded = 0;
for (int pile : piles) {
hoursNeeded += (pile + k - 1) / k; // 计算每堆香蕉需要的时间
}
return hoursNeeded <= h; // 如果总时间不超过 h 小时,则返回 true
}
}
代码解释:
minEatingSpeed
方法:- 设置
left
为 1,right
为piles
中最大值(即最大香蕉数)。 - 通过二分查找找到最小的速度
k
,使得在h
小时内能够吃完所有香蕉。
- 设置
canFinish
方法:- 给定速度
k
,计算吃掉所有香蕉所需要的时间,并与h
比较,判断是否能在h
小时内完成。
- 给定速度
[!NOTE]
在 Java 中,可以通过以下两种方式实现向上取整(即对
piles[i] / k
的结果向上取整):方法 1:使用
Math.ceil
方法
Math.ceil()
函数可以将浮动的结果向上取整为最近的整数。你需要将piles[i] / k
先转换为浮动值,之后使用Math.ceil()
方法进行取整。
double result = Math.ceil((double) piles[i] / k);
然而,这会得到一个
double
类型的结果。如果你希望得到一个int
类型的结果,可以将其转换为int
:
int result = (int) Math.ceil((double) piles[i] / k);
方法 2:使用整数运算
如果你只关心整数运算,可以通过简单的数学技巧实现向上取整,而不需要使用浮点数运算。具体来说,
(a + b - 1) / b
公式可以用来向上取整a / b
。
int result = (piles[i] + k - 1) / k;
这个公式的作用是将被除数
piles[i]
和除数k
之间的商通过加上k - 1
来保证向上取整。这是一个非常高效的方式,因为它只依赖于整数运算,不涉及浮点数计算。
本文作者:Drunker•L
本文链接:https://www.cnblogs.com/drunkerl/p/18656174
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步