1482. 制作 m 束花所需的最少天数

思路:
刚开始是想暴力双循环,但是发现思路只能解决连续且k>1的情况。想不出其他的了。
看了题目标签,二分法。但是还是没思路怎么个二分。

看了题解。之前说过二分利用的是二段性,那么我们这两段的分界设定为 最短完成采花的天数,也即答案。
(0,res)这段天数的大小是不能完成采花的,(res,+∞)z这段天数的大小是能完成采花的任务。故此能采用二分法。
因为针对的是天数的大小,那么我们的left和right就要分别针对当前区间的最小值和最大值。

那么我们二分法的流程如下:
求出当前区间的left(开花的最小的天数),right(开花的最大的天数)->获得mid大小的天数 -> 判断mid天能不能采好花 -> 能就缩小mid直到不能,此时的left和right即答案。如果不能就将left=mid+1在更大的区间寻找答案。
那么怎么判断mid天是否能采好花呢?判断函数流程如下:
定义用来记录是否连续采集k朵花的变量count,和计数能采集的最多花数量bundle -> 遍历bloomdays数组,判断元素是否小于等于mid,如果小于那么记录count+1,并判断count是否大于k,大于bundle+1,count=0。如果元素不小于mid,那么bundle=0,因为不连续了。-> 接着判断bundle是否大于等于m,是就return true。

代码:

class Solution {
public:
    bool CanMake(vector<int>& bloomDay,int m,int k,int maxday){
        int count = 0;
        int bundle = 0;
        int len=bloomDay.size();
        for(int i=0;i<len;++i){
            if(bloomDay[i]<=maxday){
                count++;
                if(count==k){
                    bundle++;
                    count = 0;
                }
            }
            else count = 0;
            if(bundle >= m) break;
        }
        return bundle >= m;
    }
    int minDays(vector<int>& bloomDay, int m, int k) {
        int day = bloomDay.size();
        if(m*k > day) return -1;
        int right = INT_MIN;
        int left = INT_MAX;
        for(int i = 0; i < day; ++i){
            left = min(left,bloomDay[i]);
            right = max(right,bloomDay[i]);
        }
        while(left<right){
            int mid = (left + right)/2;
            if(CanMake(bloomDay,m,k,mid)){
                right = mid;  //为什么right=mid?因为我们用的是left<right,此时一般来说right是左闭右开区间,即[left,right),那么mid后,就是[left,mid),[mid+1,right),那么我们此时也不再需要mid,所以用开区间,因为之前已经确定mid引起的结果了。
            }
            else left=mid+1;
        }
        return left;
    }
};
posted @ 2021-05-10 15:51  Mrsdwang  阅读(58)  评论(0编辑  收藏  举报