1. 题目来源
2. 题目解析
一般遇到带 最 字,的题目,我们可以优先考虑二分查找或者动态规划。本题是找最低运载能力,假设为 d
。那么显然小于 d
的一定不和要求,大于 d
的一定满足要求,那么就可以 二分答案 了。
那么当给定一个可能答案的时候,判断这个答案是否成立往往是简单的,也就是我们所需要实现的 check()
函数,一般就是按照题意进行暴力模拟即可。
注意:
- 本题的运载能力所在区间一定是 [最大包裹重量, 包裹重量总和],在这个区间范围内。
- 我们一般直接从
0~1e9
,来设定l、r
,但是就会出现上面这个情况,如[1,2,3,1,1] 4
理应返回 3,错误返回2
,因为它将 3 这个不合法数当做一天单独处理,这显然是不合法的。 - 如果我们的
l、r
从 [最大包裹重量, 包裹重量总和],设置并循环的话就不会出现这个情况,所以也就是这两种边界设定的不同之处。 - 计算天数的时候,维护两个变量,一个是
sum
代表一天能装的包裹重量之和,一个是t
,代表当前运载力下完成任务的天数。首先需要判断当前包裹重量是否大于了运载力,若大于则装不下,直接返回false
,否则,就不断尝试下一个能不能装,若不能装就需要新的一天来处理下一个,若能装就累加sum
,在此就是一个按题意模拟的过程。
- 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
- 空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public:
bool check(vector<int>& w, int D, int mid) {
int n = w.size();
int sum = 0, t = 1;
for (int i = 0; i < n; i ++ ) {
if (w[i] > mid) return false; // 注意,当一个包裹本身很大的时候,则该运载能力不合法
if (sum + w[i] > mid) {
sum = 0;
t ++ ;
}
sum += w[i];
}
return t <= D;
}
int shipWithinDays(vector<int>& weights, int D) {
int n = weights.size();
int l = 0, r = 1e9;
while (l < r) {
int mid = l + r >> 1;
if (check(weights, D, mid)) r = mid;
else l = mid + 1;
}
return l;
}
};