题目描述:
题目理解:
每个小时,从中选择一堆香蕉,这个香蕉里边有若干个香蕉,
1.如果选择吃掉的 根数 k (根/小时) 小于这一堆里边的,那么就只吃掉这一堆中的k个,剩下的可能下一个小时再吃
2.如果选择吃掉的根数k大于这一堆的,那么吃掉这一堆中所有的
返回在h小时内吃掉所有的香蕉的最小速度 速度:香蕉数量/时间
香蕉总数应该是固定的吧,我觉得应该主要看时间,但是这个和二分有什么关系??
但是二分搜索的本质就是在搜索自变量!!!所以题目要求什么,就把什么作为自变量x!!
总结二分搜索解决问题的步骤:
1.确定 x, f(x) , target 分别是什么,并写出函数f
2.找到 x 的取值范围作为二分搜索的搜索区间,初始化left和right变量
3.根据题目要求,确定应该使用搜索左侧还是右侧的二分
思路分析:
1.确定x,f(x),target
x:题目要求什么一般就把那个作为x自变量----->我们这里就把吃香蕉的速度k作为自变量
f(x):考虑什么东西能与x有一种关系,而且一般是单调的关系,在这个题目中有一个是速度与时间的关系,吃香蕉吃的速度越快,吃完所有香蕉的时间就越少,所以在这里速度和时间是一个单调函数关系
target : 一般是题目让你计算满足约束条件 f(x)==target 时 ,x的值,所以这里就是吃香蕉的时间限制是target,这是对f(x)返回值的最大约束
2.找到x的取值范围作为二分搜索的搜索区间,初始化left和right变量
所以要找到x的取值范围,x是吃香蕉的速度嘛,那么吃的最慢就是一根一根吃呗,最快就只能吃数组中的元素最大值
由于最大值---->我们可以是遍历数组找到最大值,然后确定下来搜索区间
也可以直接利用题目提示中的这一句话来确定搜索区间。
3.根据题目要求,确定应该使用搜索左侧还是右侧的二分搜索,写出代码
由于题目中是找到最小的速度,所以x应该尽量小,也就是满足target约束条件下的最小的那个x值,故可以分析出该题目应该是应用搜索左侧的,
不过注意:f(x)是单调递减的!!!所以在改变区间搜索时,要注意f(x)是随着x的变大而递减的,而我们要找到最小的速度,f(x)与target判断时,如果f(x)小了,就让f(x)变大,即x变小,所以应该改变右侧区域在左边找,一直记住是左开右闭的缩小区间就行了
然后关键就是往哪一边缩小区间
就这俩点..
我的写代码过程中的疑惑:
1.那么piles[]在哪里使用,他是干嘛的 ======>就在f(x)那里使用,就是当x改变时,用piles求得吃完需要耗费的所有时间
2.mid是piles的下标么??mid不应该是速度么,对啊,mid是速度 ====>这个就是因为没搞懂f()到底要求的是什么
题解:
class Solution {
public int minEatingSpeed(int[] piles, int h) {
int left=1;
int right =1000000000+1;
//由于公式里边是左开右闭,想要套公式就因该把right变大
while(left <right){
int mid =left +(right -left)/2;
if(f(piles,mid) == h){
right=mid;
}else if(f(piles,mid) <h){
right=mid;
}else if(f(piles,mid) > h){
left=mid+1;
}
}
return left;
}
//这个代表以这个速度吃完香蕉需要花多长时间
public static int f(int[] piles ,int x){
int hours=0;
for(int i=0;i<piles.length;i++){
//这个不用像这个题目里边说的,吃了还要等一个小时,然后下次再吃啥不确定
//直接就是需要两次吃完的就是两个小时,直接计算就可以
//因为这里是整除
hours+=piles[i] /x;
//如果还有剩余的就还需要加一个小时
if(piles[i] % x>0){
hours++;
}
}
return hours;
}
}
如果还有不懂的,其实抄一遍我的代码,再看看里边的注释应该懂了