1011. Capacity To Ship Packages Within D Days

思路:
这道题看到的时候没想到用二分法,主要问题在,关注的是如何从weight数组找结果,而不是从 全部搬完的天数 入手。
我们可以知道,要能把所有物品搬走,要花最长时间的每日搬运重量应该用的是 weights数组中 质量最大的元素,因为这样刚好确保了所有的物品都能搬走,并且花时间最长。 那么最短时间就是一天就搬完,那么就是weight数组求和得到的总质量作为每日允许的搬运重量。
以上的结论就能让我们从最小每日搬运重量到最大每日搬运重量二分搜索找到能在D天内刚好搬运完成的最小每日搬运重量。
那么这就满足了二分法的二段性,即该重量res,当每日搬运重量小于res,那么就无法在D天内完成,当大于res,那么就在D天内完成搬运,所以二分法成立。
因为搬运的物品是顺序递增的,那么我们如何判断这天的搬运满了呢?我们每次得到的mid就是是否搬运满足每日搬运质量的标准。
我们每次求得一次mid就得到一个每日允许的搬运重量,相当于更新了一次最小和最大每日搬运重量,所以我们每次都要循环一次weight数组,用来对不同mid进行处理,并用cur记录每日搬运的质量是否大于mid,如果大于,那么就是超过了每日搬运重量,搬运天数加一,并让cur等于0,因为记录的是每天的,大于后改天已结束。判断结束,就让cur加上weight。最后得到的天数day和D进行判断,如果day小于等于D说明搬运量太少了,那么right=mid,反之搬运量太小了,left=mid+1。
最后right和left会指向同一个位置,返回left即可。
代码:

class Solution {
public:
    int shipWithinDays(vector<int>& weights, int D) {
        int n=weights.size();
        int left=*max_element(weights.begin(),weights.end()),right=accumulate(weights.begin(),weights.end(),0);
        while(left<right){
            int cur=0,day=1;
            int mid=left+right>>1;//每个mid都是新的每日允许搬运量

            for(int weight:weights){  
                while(cur+weight>mid){  //判断该日搬运量是否大于每日允许搬运量
                    day++;              //大于那么天数加一,并让该日搬运量为0
                    cur=0;
                }
                cur += weight;  //一直加,得到每天的搬运的重量
            }

            if(day<=D) right=mid;  
            else if(day>D) left = mid+1;
        }
        return left;
    }
};
posted @ 2021-04-26 21:47  Mrsdwang  阅读(30)  评论(0)    收藏  举报