持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第31天,点击查看活动详情
刷题的日常-2022年10月29号
一天一题,保持脑子清爽
在 D 天内送达包裹的能力
来自leetcode的 1011 题,题意如下:
传送带上的包裹必须在 days 天内从一个港口运送到另一个港口。
传送带上的第 i 个包裹的重量为 weights[i]。每一天,我们都会按给出重量(weights)的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。
返回能在 days 天内将传送带上的所有包裹送达的船的最低运载能力。
示例1:
输入:weights = [1,2,3,4,5,6,7,8,9,10], days = 5
输出:15
解释:
船舶最低载重 15 就能够在 5 天内送达所有包裹,如下所示:
第 1 天:1, 2, 3, 4, 5
第 2 天:6, 7
第 3 天:8
第 4 天:9
第 5 天:10
请注意,货物必须按照给定的顺序装运,因此使用载重能力为 14 的船舶并将包装分成 (2, 3, 4, 5), (1, 6, 7), (8), (9), (10) 是不允许的。
理解题意
通过题意,我们可以将信息整理如下:
- 题目给出一个数组,代表运送货物的重量,另外给出一个天数days,代表最长的运送天数
- 要求我们在days天内 将 货物运送出去,而且货物必须是顺序运送
- 在保证货物能够在days天运送出去的同时,要保证载重能力尽可能小
- 一开始看到求最小值的时候,以为是动态规划的问题求解,然后发现不是,看了下tag,有二分,这就简单了
- 运送天数其实和船只的载重能力有关,船只载重越大,天数可能就越少。所以求最小的承载能力,就要让所有的天数都利用起来,在满足最大天数的情况下,将载重减小,直到刚好达到最大期限
做题思路
求所有货物的总重量,对总重量进行二分查找,步骤如下:
- 求货物的总质量
- 对质量进行二分查找
- 每次都求中点的值
- 校验中点是否满足最大天数的要求
- 满足的话最大质量可以减少到中点
- 否则将最小质量增大
- 返回最终结果
代码实现
代码实现如下,因为要检查logn次,每次扫描整个数组,所以时间复杂度为O(nlogn):
public class Solution {
public int shipWithinDays(int[] weights, int days) {
int max = sum(weights), min = 1, mid;
while (max > min) {
mid = min + (max - min) / 2;
if (check(mid, weights, days)) {
max = mid;
continue;
}
min = mid + 1;
}
return max;
}
private boolean check(int weight, int[] weights, int days) {
int cnt = 1, sum = 0;
for (int num : weights) {
if (num > weight) {
return false;
}
if (sum + num > weight) {
sum = num;
cnt++;
continue;
}
sum += num;
}
return cnt <= days;
}
private int sum(int[] weights) {
int res = 0;
for (int weight : weights) {
res += weight;
}
return res;
}
}