对于该问题,我们要求最小速度k,在最小速度k下计算吃完这一堆香蕉的时间:sum+=math.ceil(piles[i]/k) (根据题目要求,向上取整)
对于k,假设速度大于k,那么sum一定小于h,速度小于k,sum一定大于h
由此我们确定二分法雏形,吃一堆香蕉最快的速度是max(pile),因为题目中说每个小时会挑一堆来吃,就算提前吃完也不会吃下一堆,所以最快的速度是这一堆中最大的元素。最少也要在一个小时中吃一根,所以最小速度是1.
假设k = int((left+right)/2)
开始二分寻找最小k 值,代码如下:
class Solution:
def minEatingSpeed(self, piles: List[int], h: int) -> int:
right = max(piles)
left = 1
import math
while left <= right: #循环跳出的条件应该是left>right,也就是这个区间都遍历完
mid = int((left + right) / 2)
Sum = 0
for i in piles:
Sum += math.ceil(i / mid)
if Sum > h:
left = mid + 1
if Sum <= h:
right = mid - 1
return left #最后的left值是大于right和mid的
对于该题目的分析就是找到最小的装载能力k,船舶最大的装载能力high应该是sum(weights),也就是一天可以把全部货物送达。为了保证每天都有货物送达,船舶的最小装载能力应该是max(weights)。具体代码如下:
class Solution:
def shipWithinDays(self, weights: List[int], days: int) -> int:
high = sum(weights)
low = max(weights)
while low <= high:
k = int((low+high)/2)
Sum = 0 #装载量
i = 0
day = 0 #计算当前装载能力k下的运输天数
while i< len(weights):
Sum += weights[i]
if Sum > k and 0 <= Sum - weights[i] <= k : #确保sum此时装载的数量一定大于船舶运输能力,减去此次的重量后小于等于船舶的运输能力,这样的装载量需要day++,并且不移动i
day += 1
Sum = 0
elif Sum <= k and i == len(weights) -1 : #最后的几批货物总和一定是小于等于k的
day += 1
i += 1
else:
i += 1
if day <= days: #说明装载能力过强,需要向左移动区间,求最小值,等号放在high的移动区间上
high = k - 1
if day > days: #说明装载能力过弱,需要向右移动区间
low = k + 1
return low