题目
思路
问题1: 如何判断载重量为load
的船至少需要多少天能够运送所有包裹呢?
我们只需要遍历一次weights数组,从第一个元素开始求和,直到和大于load
(尽可能把船装满),此时可以确定当前元素之前的元素应该安排在一天运送。我们重置和为0,并添加当前元素(因为当前元素加到前一天导致船超载),继续遍历数组后续元素即可得到所需的天数。
如果某个元素超过了load则结果为无限大(INT_MAX)
问题2:我们如何确定在D天内送完所有包裹需要的船的最小载重量呢?
由于我们已经解决了上一个问题,我们可以将载重量设置为1并逐渐增加进行尝试,直到所需的运输天数刚刚小于等于D。不过该方法可能会超时,我们可以通过二分搜索的方式来更快的找到合适的载重量。
首先我们确定载重量的上下界,上界为所有的货物重量之和,下界为最大的单个货物重量。使用二分搜索,如果当前测试载重量load
需要的运输天数大于D,则将搜索下界改为load + 1
(因为当前load
值必定不会是最终结果)。如果当前测试的load
值小于或者等于D
,则将搜索上界设置为load
, 直到上下界相等,则是我们所求的最终结果。
当运输天数<=D时,当前测试的载重量不一定是最小载重量(但可能是),因此我们还需要尝试减小载重量
load
进行测试,但由于当前load
也可能是最小载重量,因此我们设置上界为load
而不是load-1
;
代码
class Solution {
public:
int shipWithinDays(vector<int>& weights, int D) {
int load = 0;
int i = 0;
int low = 0;
int high = 0;
for(int n : weights) {
high += n;
if (n > low) {
low = n;
}
}
while(high > low) {
load = (high + low) / 2;
int day = day_used(load, weights);
if (day <= D) {
high = load;
} else if (day > D) {
low = load + 1;
}
}
return high;
}
int day_used(int load, vector<int>& weights) {
int day = 0;
int current = 0;
for(int n : weights) {
if (n > load) {
return INT_MAX;
}
current += n;
if (current > load) {
day++;
current = n;
}
}
if (current > 0) {
day++;
}
return day;
}
};