0
点赞
收藏
分享

微信扫一扫

【二分--分堆】 -LeetCode-1011. 在 D 天内送达包裹的能力

一葉_code 2022-04-08 阅读 37

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
提示:

  • 1 < = d a y s < = w e i g h t s . l e n g t h < = 5 ∗ 1 0 4 1 <= days <= weights.length <= 5 * 10^4 1<=days<=weights.length<=5104
  • 1 < = w e i g h t s [ i ] < = 500 1 <= weights[i] <= 500 1<=weights[i]<=500

二分

思路 🤔

  1. 船所需的最低运载能力:为 max,即最起码能保证一次能把 w e i g h t s weights weights中最大的货物运输到另一港口;

  2. 船所需的最高运载能力:为 sum,即一次就把全部货物运输到另一港口;

  3. 开始二分

    • 当按照运载能力mid装船时,可以将所有货物都能在 d a y s days days 天内都运输完毕,则“尝试”更小的装载量是否可以满足,即 right = mid - 1
    • 否则,则说明当前 mid 运载能力不足,则需要船具有更大的运载能力,即 left = mid + 1

class Solution {
    public int shipWithinDays(int[] weights, int days) {
        int max = 0;
        int sum = 0;
        for (int weight : weights) {
            max = Math.max(max, weight);
            sum += weight;
        }
        int left = max;  // 最小运载能力
        int right = sum; // 最大运载能力
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (check(weights, mid, days)) { // 按照mid装船时,可以满足,则“尝试”更小的装载量是否可以满足,即mid - 1
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }

    // 将weight
    boolean check(int[] weights, int target, int days) {
        int cnt = 0;
        for (int i = 0; i < weights.length; ) {
            int sum = 0;
            // 找一堆连续“最接近”(但不超过)target的总和
            while (i < weights.length && sum + weights[i] <= target) {
                sum += weights[i++];
            }
            cnt++;
        }
        return cnt <= days;
    }

    public static void main(String[] args) {
        int[] nums = {1,2,3,4,5,6,7,8,9,10};
        int days = 5;
        System.out.println(new Solution().shipWithinDays(nums, days));
    }
}

在这里插入图片描述

410. 分割数组的最大值

在这里插入图片描述
在这里插入图片描述

二分

  • 本题和 1011. 在 D 天内送达包裹的能力 基本一致
class Solution {
    public int splitArray(int[] nums, int m) {
        int n = nums.length;
        int max = 0;
        int sum = 0;
        for (int i : nums) {
            sum += i;
            max = Math.max(max, i);
        }
        int left = max;
        int right = sum;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (check(nums, mid, m)) { // 尝试更小的“分堆和”
                right = mid - 1;
            } else {    
                left = mid + 1;
            }
        }
        return left;
    }

    boolean check(int[] nums, int target, int m) {
        int cnt = 0;
        for (int i = 0; i < nums.length; ) {
            int sum = 0;
            while (i < nums.length && sum + nums[i] <= target) {
                sum += nums[i++];
            }
            cnt++; // 增加“堆数”
        }
        return cnt <= m;
    }
}

在这里插入图片描述

  • 参考:三叶姐 题解
举报

相关推荐

0 条评论