爱吃香蕉的珂珂,包裹运输问题——二分查找的变形

本文通过LeetCode875题,探讨如何应用二分查找解决珂珂吃香蕉的问题,以及与之相关的包裹运输问题。通过分析,我们可以发现这类问题与求解最小载重和最快速度的运输方案密切相关。通过转换思路,可以将复杂问题简化为已知问题的求解。

LeetCode875
题目表述:
在这里插入图片描述
题目的意思是,珂珂一小时最多能吃完一堆,如果吃完了还有时间,她也不会再吃了。因此最小速度的最大值正是数组中的最大数,最小值是1。

class Solution {
    public int minEatingSpeed(int[] piles, int h) {
        //1.找到一堆中的最大值
        int max = 0;
        for(int number : piles){
            max = Math.max(max,number);
        }

        //2.二分查找最小的h
        int left = 1;
        int right = max;
        while(left <= right){
            int time = 0;
            int mid = (left + right) >> 1;
            for(int number : piles){
                time += (number / mid) + ((number % mid > 0) ? 1 : 0);
            }
            if(time <= h){
                right = mid - 1; //说明可以再少吃一点
            }else{
                left = mid + 1; //说明需要多吃一点
            }
        }
        return left;
    }
}

与这题相似的包裹运输问题:
LeetCode1011
在这里插入图片描述
这里每天运输的最小载重的最小值是数组最小数,因为包裹不能拆开来运,最小载重的最大值是数组之和,因为最快的情况就是一天把所有包裹运完。

class Solution {
    public int shipWithinDays(int[] weights, int D) {
        //1.找到载重量的最大值和最小值
        int left = 0;
        int right = 0;
        for(int n : weights){
            left = Math.max(left,n);
            right += n;
        }

        //二分找到最小载重量
        while(left <= right){
            int sum = 0;  //统计当天的运输总重
            int days = 1; //统计需要的天数
            int mid = (left + right) >> 1;
            for(int n : weights){ //计算总共需要多少天
                sum += n;
                if(sum > mid){
                    sum = n;
                    days++;
                }
            }
            if(days <= D){
                right = mid - 1;
            }else{
                left = mid + 1;
            }
        }
        return left;
    }
}

LeetCode410
在这里插入图片描述
这个题乍一看很难,因为不知道要怎么分割数组,但是其实我们并不需要关心如何分割数组,只需要知道这些子数组的最大值,能不能满足将数组分成m个。这么一看是不是瞬间就转化成上面那道包裹运输问题了。代码一模一样。

class Solution {
    public int splitArray(int[] nums, int m) {
        //1、得到最小值和最大值
        int left = 0;
        int right = 0;
        for(int n : nums){
            left = Math.max(left,n);
            right += n;
        }
        while(left <= right){
            int sum = 0;
            int h = 1;
            int mid = (left + right) >> 1;
            for(int n : nums){
                sum += n;
                if(sum > mid){
                    sum = n;
                    h++;
                }
            }
            if(h <= m){
                right = mid - 1;
            }else{
                left = mid + 1;
            }
        }
        return left;
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值