具体题目参考leetcode 1011.在D天内送达包裹的能力
我的解法:
根据题目可以看出,最低运载能力肯定 ≥ 这批包裹中重量最大的,因此可以先找出重量最大的包裹;
然后从第一个包裹开始计算,如果加上下一个包裹的重量大于最低运载能力,那么天数+1,下一个包裹按照上述方法计算;如果不大于,那么继续累加。最后判断天数是否超过所需天数即可。
class Solution {
public int shipWithinDays(int[] weights, int D) {
int maxWeigth=0;
for(int value:weights) {//找出最大重量 最低载重临界
if(value>maxWeigth) {
maxWeigth=value;
}
}
int days=0;
while(true) {
int sumWeight=0;
for(int value:weights) {//判断
if(sumWeight+value>maxWeigth) {
days++;
sumWeight=value;
}
else sumWeight+=value;
}
if(days<=D) {//是否满足题意
return maxWeigth;
}
else maxWeigth++;
}
retrun 0;
}
}
代码分析:
整体算法思想还是暴力穷举+贪心算法,但会出现超出时间限制的错误,不能大规模的解决问题。
二分查找转化为判定:
贪心算法那部分依然不变,但是不采用暴力穷举了,而是变成二分查找判定来降低时间复杂度。
因此首先需要确定二分查找的边界:
左边界:这批包裹中的最大重量; 右边界:这批包裹的总重量。
判定方式:
如果当前最低运载量所需天数大于题目天数 那么右边界为当前最低运载量
如果当前最低运载量所需天书小于题目天数 那么左边界为当前最低运载量
class Solution {
public int shipWithinDays(int[] weights, int D) {
// 确定二分查找左右边界
int left = Arrays.stream(weights).max().getAsInt();
int right = Arrays.stream(weights).sum();
while (left < right) {
int mid = left + (right - left) / 2;//避免溢出
// need 为需要运送的天数
// cur 为当前这一天已经运送的包裹重量之和
int need = 1, cur = 0;
for (int weight : weights) {
if (cur + weight > mid) {
++need;
cur = 0;
}
cur += weight;
}
if (need <= D) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
}