题目来源:力扣
题目描述:
传送带上的包裹必须在 D 天内从一个港口运送到另一个港口。
传送带上的第 i 个包裹的重量为 weights[i]。每一天,我们都会按给出重量的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。
返回能在 D 天内将传送带上的所有包裹送达的船的最低运载能力。
该题目与另一力扣习题吃香蕉类似,大家如果感兴趣可以比较一下.
审题:
1.题目中提到包裹必须按照先后顺序装载,因此我们很容易计算给定运载能力下,完成所有货物运输所需的时间.
2. 题目要求返回能在指定时间内完成所有包裹送达的船的最低运载能力.
由于之前做过类似的题目,如吃香蕉.因此题目做到这,我便想到了将这道题转化为在存在重复至条件下,使用二分搜索查找对应值的最小下标位置.
使用二分搜索我们需要确定搜索的上下边界,对于这道题,其运载能力下边界为最重的货物重量,因为如果运载能力小于最重的货物重量, 则该货物永远无法被运载.由于所需时间以日为单位,因此最少的运输时间为1日,对应的运载能力上界便是所有货物重量之和.
基于以上,我们算法实现如下节.
java算法实现:
class Solution {
//计算运载能力为capacity时,运载完所有货物所需时间
private int dayConsume(int[] weights, int capacity){
int days = 0;
int capacityRemain = capacity;
for(int i = 0; i < weights.length; i++){
if(capacityRemain < weights[i]){ //如果剩余容量不够装载当前货物,则当前货物及后序货物只能安排在下一日装载
days++;
capacityRemain = capacity;
}
capacityRemain -= weights[i];
}
days++;
return days;
}
//使用二分搜索
public int shipWithinDays(int[] weights, int D) {
int toatlWeights = 0;
int maxWeight = 0;
for(int i: weights){
if(i > maxWeight)
maxWeight = i;
toatlWeights += i;
}
int lo = maxWeight;
int hi = toatlWeights+1;
while(lo < hi){
int mid = lo + (hi-lo) / 2;
int days = dayConsume(weights, mid);
if(days <= D) //如果days <= D, 则可能的搜索范围包括[lo, mid], 如果在[lo, mid)内未搜索到,则返回mid
hi = mid;
else //如果days > D, 则可能的搜索范围为[mid+1, hi)
lo = mid+1;
}
return hi;
}
}