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;
}
};