Leetcode_1011.在D天内送达包裹的能力————二分法的第一次arise

传送带上的包裹必须在 D 天内从一个港口运送到另一个港口。
传送带上的第 i 个包裹的重量为 weights[i]。每一天,我们都会按给出重量的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。
返回能在 D 天内将传送带上的所有包裹送达的船的最低运载能力。

原题地址:在D天内送达包裹的能力

  • 我的超时题解
class Solution {
public:
    int shipWithinDays(vector<int>& weights, int D) {
        int _chazhi   = weights.size() - D;
        int _maxwt    = 0;
        int _capacity = 0;
        int _i        = 0;
        int _tempsum  = 0;
        int _manydays = 0;
        for (int i = 0; i < weights.size(); ++i) {
            if (_maxwt < weights[i]){
                _maxwt = weights[i];
            }
        }
        _capacity = _maxwt;

        while(1){
            while (_i < weights.size()){
                if ((weights[_i]+_tempsum) <= _capacity){
                    _tempsum+=weights[_i];
                    _i++;
                    if(_i == weights.size()){
                        _manydays++;
                    }
                }
                else{
    //                _i++;
                    _manydays++;
                    _tempsum=0;
                    continue;
                }
            }
            if(_manydays <= D){
                break;
            }
            else{
                _capacity++;
                _tempsum  = 0;
                _i        = 0;
                _manydays = 0;
            }
        }//无限循环
        return _capacity;
    }
};

暴力法,我没了,暴力不给过。

  • 大佬的DP做法
class Solution {
public:
    int shipWithinDays(vector<int>& weights, int D) {
        // 确定二分查找左右边界
        int left = *max_element(weights.begin(), weights.end()), right = accumulate(weights.begin(), weights.end(), 0);
        while (left < right) {
            int mid = (left + right) / 2;
            // need 为需要运送的天数
            // cur 为当前这一天已经运送的包裹重量之和
            int need = 1, cur = 0;
            for (int weight: weights) {
                if (cur + weight > mid) {
                    ++need;
                    cur = 0;
                }
                cur += weight;
            }
            if (need <= D) {
                right = mid;
            }
            else {
                left = mid + 1;
            }
        }
        return left;
    }
};

//作者:LeetCode-Solution

仔细思考并看题解之后理解了大佬的部分思路。
首先,已知运货能力最小是最重货物,因为若达不到最重货物,货物都运不完。
其次,可以以二分法为基础,以所有货物重量之和进行二分,这样逼近正确答案的速度更快,是log复杂度。不像我的暴力解法,是通过线性检索。
再者,因为最小运输能力是最重货物,我们绝对可以将所有货物运走,只是时间的问题。即利用这一段代码来求解目前所需天数:

 int mid = (left + right) / 2;//取mid为当前的运输能力
            // need 为需要运送的天数
            // cur 为当前这一天已经运送的包裹重量之和
 for (int weight: weights) 
{
   if (cur + weight > mid) {
        ++need;
        cur = 0;
    }
    cur += weight;
}

因为mid是当前运输能力,在cur + weight > mid 的时候天数加 1 ,而初始化 cur(当前运输量)。
最后只需要判断 need(所需天数) 与D的关系,比目标天数D少的话,就将右边界左移,因为我们要求尽量接近D,运输能力不是越强越好。 比目标天数D多的话,就将左边界右移(即提高运输能力,减少天数,因为D天正好运完是底线)。
最后返回left,老模板了。
二分方法第一次在这实际应用,这里顺便加一下二分法模板。
—————————————————————————————————————————————————————

//二分查找
int lower_bound(int A[], int left, int right, int x){//还是利用角标作用排序后的数组
    int mid;//mid作为left和right的中点
    while (left < right){// 对[left,right]来说,left==right 意味着找到唯一位置
        mid = (left + right)/2;//取到中点
        if (A[mid] >= x){//------------------>数组中对应位置的数字比目标数字大,肯定x就在A[mid]的左方
            right = mid; //因此有right = mid,即缩小区间
        } else{
            left  = mid+1;
        }
    }
    if( A[left] ==x ){
        return left;
    }
    else{
        return -10086;
    }//原算法没考虑找不到吧
    return left;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值