题目
珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。
珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。
珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。
返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。
示例
思路
题目是寻找最小速度
1.我们可以找到平均速度,以平均速度最为速度下限,寻找最小速度,
以速度下限为基准,逐一向上寻找,但是显然消耗时间大。
2.以二分法进行查找,进行优化,可以降低时间消耗
// 这里求的速度平均 其实是香蕉总数不变的情况下算出来珂珂每个小时应该吃这么多,为什么它可以作为最小基准呢?
// 是因为一堆香蕉可以分成好几次吃,而且每小时只能吃一堆香蕉,这是前提
// 如果遇到一堆香蕉个数小于珂珂每个小时的速度的时候,接下来再以当前速度吃香蕉的话,就吃不完了
// 所以一开始求得的平均值就是一个最小速度基准,另外上边这番解释也一定程度上论证了为什么以平均值作为最小速度值是可行的
代码
1.逐一查找
int GetAvarageNum(int* piles, int pilesSize, int time)
{
int i;
double sum = 0;
for(i = 0; i < pilesSize; i++){
sum += piles[i];
}
return (int)(sum / time);
}
void EatBranana(double brananas, double speed, int *time)
{
// 一次能吃完吗?如果可以,那么这一小时就吃这一堆,有余力也不多吃另一堆了
if (brananas <= speed){
*time = *time - 1;
return;
}
//一次吃不完 因为最终肯定要都吃完的,所以这里就只能分成好几个小时来吃一堆香蕉咯
*time = *time - ceil(brananas / speed);
return;
}
int minEatingSpeed(int* piles, int pilesSize, int H){
// 这里求的速度平均 其实是香蕉总数不变的情况下算出来珂珂每个小时应该吃这么多,为什么它可以作为最小基准呢?
// 是因为一堆香蕉可以分成好几次吃,而且每小时只能吃一堆香蕉,这是前提
// 如果遇到一堆香蕉个数小于珂珂每个小时的速度的时候,接下来再以当前速度吃香蕉的话,就吃不完了
// 所以一开始求得的平均值就是一个最小速度基准,另外上边这番解释也一定程度上论证了为什么以平均值作为最小速度值是可行的
int i;
int time = H;
int K = GetAvarageNum(piles, pilesSize, time);
// 吃香蕉实验
while(1){
for(i = 0; i < pilesSize; i++){
EatBranana(piles[i], K, &time);
}
// 时间还有剩余 或者刚刚好 说明能吃完
if (time >= 0){
return K;
}
// 没吃完 速度加 1 继续实验
K++;
time = H;
}
return 0;
}
2.二分法
#define MAX(a, b) ((a) > (b) ? (a) : (b))
long getTime(const int* piles, int pilesSize, int speed) {
long time = 0;
for (int i = 0; i < pilesSize; i++) {
int curTime = (piles[i] + speed - 1) / speed;//向上取整
time += curTime;
}
return time;
}
int minEatingSpeed(int* piles, int pilesSize, int h) {
int low = 1;
int high = 0;
for (int i = 0; i < pilesSize; i++) {
high = MAX(high, piles[i]);
}
while (low < high) {
int speed = (high - low) / 2 + low;
long time = getTime(piles, pilesSize, speed);
if (time <= h) {
high = speed;
} else {
low = speed + 1;
}
}
return low;
}
时间空间复杂度
1.逐一查找
2.二分法