[前端]_一起刷leetcode 1011. 在 D 天内送达包裹的能力

106 阅读3分钟

这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战

题目

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

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

示例 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], D = 4
输出: 3
解释:
第 1 天:1
第 2 天:2
第 3 天:3
第 4 天:1, 1

 

提示:

  • 1 <= days <= weights.length <= 5 * 104
  • 1 <= weights[i] <= 500

思路

  1. 这道题目也是二分查找的一道经典题目,二分查找不单单应用于找索引元素,在有序链表中来找到某个元素,我们也可以把取值范围界定好左右边界,然后通过二分法来快速找到某个值;
  2. 首先我们对整个数组进行一次求和操作,得出总数sum,然后平均分给days天,求出来的平均值就是我们的左边界left,也意味着最好的情况是刚好大家平均分完的次数,最坏的情况也就是所有的元素全部得同一天运送完成,所以我们的右边界right也就等于总数sum
  3. 然后左右边界确定了之后,我们只需要通过二分查找来快速定位到最左边的右边界即可:
    • 如果当前二分查找的天数不能完全运输货物,左边界 = 当前值 + 1
    • 如果当前二分查找的天数能够完全运输货物,右边界 = 当前值
  4. 这里要明确右边界不能减一,因为左边不够的时候肯定要往右边查找,右边够了左边不一定还够;
  5. 然后循环执行到左右边界相遇的时候,这时候我们的坐标就是最左边的右边界了。

实现

/**
 * @param {number[]} weights
 * @param {number} days
 * @return {number}
 */
function shipWithinDays(weights, days) {
    const sum = weights.reduce((total, cur) => total += cur);
    let left = Math.floor(sum / days),
        right = sum;

    while (left < right) {
        const mid = left + right >> 1;
        if (validateTarget(weights, days, mid)) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }

    return left;
}

// 验证当前值是否能运输所有包裹
function validateTarget(nums, days, target) {
    let count = 0;

    for (let i = 0; i < nums.length; i++) {
        // 如果单一项都运输不了说明不行
        if (nums[i] > target) {
            return false;
        }

        // 每天尽可能多放,放不下就留到第二天
        if (count + nums[i] <= target) {
            count += nums[i];
        } else {
            // 直到天数不够用了,返回false
            if (days > 1) {
                days--;
                count = nums[i];
            } else {
                return false;
            }
        }
    }

    return true;
}

结果

image.png

看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。