Leetcode 875. 爱吃香蕉的珂珂(中等) 1011. 在D天内送达包裹的能力(中等) 二分查找高级用法

labuladong讲解

代码框架

// 函数 f 是关于自变量 x 的单调函数
int f(int x) {
    // ...
}

// 主函数,在 f(x) == target 的约束下求 x 的最值
int solution(int[] nums, int target) {
    if (nums.length == 0) return -1;
    // 问自己:自变量 x 的最小值是多少?
    int left = ...;
    // 问自己:自变量 x 的最大值是多少?
    int right = ...;

    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (f(mid) == target) {
            // 问自己:题目是求左边界还是右边界?
            // ...
        } else if (f(mid) < target) {
            // 问自己:怎么让 f(x) 大一点?
            // ...
        } else if (f(mid) > target) {
            // 问自己:怎么让 f(x) 小一点?
            // ...
        }
    }
    return left;
}

 

875. 爱吃香蕉的珂珂(中等)

题目:

 

 思路:

珂珂每小时最多只能吃一堆香蕉,如果吃不完的话留到下一小时再吃;如果吃完了这一堆还有胃口,也只会等到下一小时才会吃下一堆。

他想在警卫回来之前吃完所有香蕉,让我们确定吃香蕉的最小速度K

 

 

f函数为单调递减,我们要求左侧边界

class Solution {
public:
    int minEatingSpeed(vector<int>& piles, int h) {
        //最小速度1
        int left=1;
        //最大速度10^9
        int right=1000000000;
        while(left<=right){
            int mid=left+(right-left)/2;
            //当f<h时,增大f,需要减小k,也就是mid要减小,缩短右边界
            if(f(piles,mid)<h)
                right=mid-1;
            else if(f(piles,mid)>h)//当f>h时,减小f,需要增大k,也就是mid要增加,左边界增大
                left=mid+1;
            else
                right=mid-1;//f==h时,我们求k最小值,也就是最左侧,所以缩小右边界
        }
        return left;
    }
    //单调递减函数,K吃的速度越大,耗时越短
    int f(vector<int>& piles, int k){
        int h=0;
        for(int i=0;i<piles.size();++i){
            //吃完一堆的耗时,不满K按1小时算
            h+=piles[i]/k;
            if(piles[i]%k>0){
                h++;
            }
        }
        return h;
    }
};

 

1011. 在D天内送达包裹的能力(中等)

题目:

 

 思路:

要在D天内按顺序运输完所有货物,货物不可分割,如何确定运输的最小载重

f函数为单调递减函数,target显然就是运输天数D,我们要在f(x) == D的约束下,算出船的最小载重

船的最小载重应该是weights数组中元素的最大值,因为每次至少得装一件货物走,不能说装不下嘛。

最大载重显然就是weights数组所有元素之和,也就是一次把所有货物都装走

现在我们确定了自变量x是船的载重能力,f(x)是单调递减的函数,target就是运输总天数限制D,题目要我们计算船的最小载重,也就是x要尽可能小

 

 这就是搜索左侧边界的二分搜索

class Solution {
public:
    int shipWithinDays(vector<int>& weights, int days) {
        int left=0,right=0;
        for(int i=0;i<weights.size();++i){
            left=max(left,weights[i]);
            right+=weights[i];
        }
        while(left<=right){
            int mid=left+(right-left)/2;
            if(f(weights,mid)>days)
                left=mid+1;
            else if(f(weights,mid)<days)
                right=mid-1;
            else 
                right=mid-1;
        }
        return left;
    }
    // 定义:当运载能力为 x 时,需要 f(x) 天运完所有货物
    // f(x) 随着 x 的增加单调递减
    int f(vector<int>& weights, int d){
        int days=0;
        for(int i=0;i<weights.size();){
            //顺序累加重量直到超量
            int w=0;
            while(i<weights.size()){
                w+=weights[i];
                if(w>d) break;
                i++;
            }
            days++;
        }
        return days;
    }
};

 

posted @ 2022-02-27 23:07  鸭子船长  阅读(56)  评论(0编辑  收藏  举报