Skip to content

1011. 在 D 天内送达包裹的能力 Medium

传送带上的包裹必须在 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) 是不允许的。

示例 2:
输入:weights = [3,2,2,4,1,4], days = 3
输出:6
解释:
船舶最低载重 6 就能够在 3 天内送达所有包裹,如下所示:
第 1 天:3, 2
第 2 天:2, 4
第 3 天:1, 4

示例 3:
输入:weights = [1,2,3,1,1], days = 4
输出:3
解释:
第 1 天:1
第 2 天:2
第 3 天:3
第 4 天:1, 1

解题思路

输入: 一个整数数组 weights 和一个正整数 days

输出: 返回能在 days 天内将传送带上的所有包裹送达的船的最低运载能力。

本题属于二分答案类问题,也属于 求最小 问题。

我们需要写一个 check 函数来判断在时间 days 内,每座船最大可以运输 weight 重量,当要运输的量超过 weight 时增加一天并清空当前运输量,最后判断需要的天数是否 <= days

  • 左边界(最小运输量):至少要大于等于 max(weights)
  • 右边界(最大运输量):最多需要 sum(weights)(一天运完)

最后在左右边界内通过二分法找到最小的满足条件的值

代码实现

python
class Solution:
    def shipWithinDays(self, weights: List[int], days: int) -> int:
        # 检查当船的载重为 weight 时,能否在 days 天内运完所有包裹
        def can_ship_with_capacity(weight: int) -> bool:
            day_count = 1      # 起始为第一天
            curr_load = 0      # 当前这一天已经装载的重量
            
            for w in weights:
                # 如果当前包裹加进去超重了,必须换一天
                if curr_load + w > weight:
                    day_count += 1
                    curr_load = 0
                curr_load += w  # 当前包裹装上船
            
            return day_count <= days  # 如果天数不超过限制,说明这个容量是可行的

        # 初始化二分查找的左右边界
        left = max(weights)          # 船的最小容量至少要能装下最重的包裹
        right = sum(weights)         # 船的最大容量就是一天运完全部包裹
        answer = right               # 初始化答案为最大值

        # 二分查找最小可行的船容量
        while left <= right:
            mid = (left + right) // 2  # 当前尝试的船容量
            if can_ship_with_capacity(mid):
                answer = mid           # 记录当前可行解,并尝试更小的容量
                right = mid - 1
            else:
                left = mid + 1         # 当前容量不够,尝试更大的容量

        return answer
javascript
/**
 * @param {number[]} weights
 * @param {number} days
 * @return {number}
 */
var shipWithinDays = function(weights, days) {
    function canShip(capacity) {
        let total = 0;
        let dayCount = 1;

        for (let w of weights) {
            if (total + w > capacity) {
                total = 0;
                dayCount += 1;
            }
            total += w;
        }

        return dayCount <= days;
    }

    let left = Math.max(...weights);
    let right = weights.reduce((acc, curr) => acc + curr, 0);
    let ans = right;

    while (left <= right) {
        const mid = Math.floor((left + right) / 2);

        if (canShip(mid)) {
            ans = mid;
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }

    return ans;
};

复杂度分析

时间复杂度:O(N * log W) N 包裹数量,W 为最大包裹重量

空间复杂度:O(1)

链接

1011 国际版

1011 中文版