问题
要将传送带上的物品在D天内送到目的地。给定一个整形数组weights,每一个元素weights[i]表示第i个物品的重量。现在要求得能在D天内运送货物的船的最小承重。
实例:
输入: weights = [1,2,3,4,5,6,7,8,9,10], D = 5
输出: 15
解释:
A ship capacity of 15 is the minimum to ship all the packages in 5 days like this:
1st day: 1, 2, 3, 4, 5
2nd day: 6, 7
3rd day: 8
4th day: 9
5th day: 10
传送带上的货物必须按照顺序送出。
解析
该问题可以转换成二分查找问题——即在承重范围内确定货船的最小承重。首先确定承重范围,承重范围最小是所有货物的最大值(小于它那就所有货物都运不出去了),承重范围最大为排序后的前n个数之后,n=temp.length/D + temp.length%D。
得到区间范围只有就可以进行二分查找,找到最适合的承重值。这里要做一些简单的修改。
//承重满足要求,但是还需要继续往左探索,找到最小的承重值
if(com==D){
//to do
}
//承重过小,往右探索
else if{
//to do
}
//承重过大,往左探索
else{
//to do
}
Java代码
public int shipWithinDays(int[] weights, int D) {
int temp[] = Arrays.copyOfRange(weights, 0, weights.length);
Arrays.sort(temp);
int max_one =temp[temp.length-1];
int n = temp.length/D + temp.length%D;
int max_pair = 0;
for(int i=temp.length-1;i>=temp.length-n;i--){
max_pair +=temp[i];
}
//然后将问题转化成二分查找问题
while(max_one<=max_pair){
int mid = (max_one + max_pair)/2;
int com = judge(weights, mid);
if(com==D){
if(judge(weights, mid-1)>D) return mid;
else max_pair = mid-1;
}
else if(com>D){
max_one = mid + 1;
}
else if(com<D){
max_pair = mid -1;
}
}
return max_one;
}
//用于判断当前位置时候能装入
public int judge(int[] weights, int mid){
int count=0;
int ans =0;
for(int i=0;i<weights.length;i++){
ans +=weights[i];
if(ans>mid){
ans = weights[i];
count++;
}
else if(ans==mid){
ans =0;
count++;
}
if(i==weights.length-1&&ans!=0) {
count++;
}
}
return count;
}
该算法的时间复杂度为O(nlgn),空间复杂度为O(n);