1、描述
给你一个整数数组 bloomDay,以及两个整数 m 和 k 。
现需要制作 m 束花。制作花束时,需要使用花园中 相邻的 k 朵花 。
花园中有 n 朵花,第 i 朵花会在 bloomDay[i] 时盛开,恰好 可以用于 一束 花中。
请你返回从花园中摘 m 束花需要等待的最少的天数。如果不能摘到 m 束花则返回 -1 。
示例 1:
输入:bloomDay = [1,10,3,10,2], m = 3, k = 1
输出:3
解释:让我们一起观察这三天的花开过程,x 表示花开,而 _ 表示花还未开。
现在需要制作 3 束花,每束只需要 1 朵。
1 天后:[x, _, _, _, _] // 只能制作 1 束花
2 天后:[x, _, _, _, x] // 只能制作 2 束花
3 天后:[x, _, x, _, x] // 可以制作 3 束花,答案为 3
来源:力扣(LeetCode)
链接
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2、关键字
数组,符合条件,最少,相邻,
3、思路、
1、无头绪,二分,
2、寻找二分的边界,0,到数组最大值,就是天数,特判直接不符合条件的情况,
3、搞一个辅助函数,来判断当前天数,能不能找到连续的花,构成m束花,
4、二分,while(l < r)不写等号,如果等号就无限循环了,
5、内部找结果时候,不要左右都变化,if ,else最好 l = mid + 1, r = mid;别写成l = mid + 1, r = mid - 1 ;前者虽然可能多循环一次,但是能找到正确结果,而后者不能.
6、辅助函数中,求相邻的花,时候,别搞两层循环,会时间超限,直接一遍找满足条件的情况就好了,
// 这里两层循环,时间超限
bool yesNo(vector<int>& bloomDay,int m, int k, int day){
int n = bloomDay.size();
int kk = k;
int num = 0;
for (int i = 0; i < n; i++){
bool flag = false;
int j;
for( j = i; j< kk + i && j < n; j++){ // 两层循环
if(bloomDay[j] > day){
//i = j;
break;
}
}
if(j == kk + i){
num ++;
i += k - 1;
}
}
return num >= m;
}
// 这种可以
bool yesNo(vector<int>& bloomDay,int m, int k, int day){
int n = bloomDay.size();
//int kk = k;
int flower = 0; // 当前 束, 花的个数
int num = 0; // 几束花
for (int i = 0; i < n && num <=m; i++){ // && num <=m 优化时间,如果有就直接不再找了,
if(bloomDay[i] <= day){ // 符合条件的花
flower++;
if(flower == k){
num++;
flower=0;
}
}
else{
flower = 0;
}
}
return num >= m;
}
4、notes
最小也想下二分。拆分出一个辅助函数
5、复杂度
时间:O(nlogh),
n是数组长度,h是数组的最大值,遍历找最大值h,需要O(N),
二分找满足条件的需要O(logh)二分查找的迭代次数, 每次寻找能否构成花束,又是O(N),
所以O(N) + O(N logh)
空间:O(1);
6、code
class Solution {
public:
bool yesNo(vector<int>& bloomDay,int m, int k, int day){
int n = bloomDay.size();
//int kk = k;
int flower = 0; // 当前 束, 花的个数
int num = 0; // 几束花
for (int i = 0; i < n && num <=m; i++){ // && num <=m 优化时间,如果有就直接不再找了,
if(bloomDay[i] <= day){ // 符合条件的花
flower++;
if(flower == k){
num++;
flower=0;
}
}
else{
flower = 0;
}
}
return num >= m;
}
int minDays(vector<int>& bloomDay, int m, int k) {
int n = bloomDay.size();
if (n < m * k) return -1;
int l = 0 ;
int r = bloomDay[0];
for(auto val : bloomDay){ // 求二分的右边界
if(val > r){
r = val;
}
}
int res = r;
//int mid = 0;
while(l < r){ // 如果是带等号就无限循环了
int mid = l + (r - l) / 2;
if(yesNo(bloomDay,m,k,mid)){
res = mid;
//r = mid - 1; // 这样写通不过
r = mid;
}
else{
l = mid + 1;
}
}
return res;
}
};