刷题的日常-在 D 天内送达包裹的能力

180 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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, 52 天:6, 73 天:84 天:95 天: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;
    }
}

image.png