题目描述
给你一个整数数组 bloomDay
,以及两个整数 m
和 k
。
现需要制作 m
束花。制作花束时,需要使用花园中相邻的 k
朵花 。
花园中有 n
朵花,第 i
朵花会在 bloomDay[i]
时盛开,恰好 可以用于 一束 花中。
请你返回从花园中摘 m
束花需要等待的最少的天数。如果不能摘到 m
束花则返回 -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
输入:bloomDay = [1,10,3,10,2], m = 3, k = 2
输出:-1
解释:要制作 3 束花,每束需要 2 朵花,也就是一共需要 6 朵花。而花园中只有 5 朵花,
无法满足制作要求,返回-1
输入:bloomDay = [7,7,7,7,12,7,7], m = 2, k = 3
输出:12
解释:要制作 2 束花,每束需要 3 朵。
花园在 7 天后和 12 天后的情况如下:
7 天后:[x, x, x, x, _, x, x]
可以用前 3 朵盛开的花制作第一束花。但不能使用后 3 朵盛开的花,因为它们不相邻。
12 天后:[x, x, x, x, x, x, x]
显然,我们可以用不同的方式制作两束花。
输入:bloomDay = [1000000000,1000000000], m = 1, k = 1
输出:1000000000
解释:需要等 1000000000 天才能采到花来制作花束
输入:bloomDay = [1,10,2,9,3,8,4,7,5,6], m = 4, k = 2
输出:9
限制
- $bloomDay.length = n$
- $1 \leq n \leq 10^5$
- $1 \leq bloomDay[i] \leq 10^9$
- $1 \leq m \leq 10^6$
- $1 \leq k \leq n$
算法
(二分) $O(nlog(n))$
- 当$m * k$比数组长度还要大时,是一定不够制作$m$束花的
- 若等待$t$天后恰好能制作$m$束花,那么$t$天之后的每一天都能制作$m$束花,而$t$天之前则不能,满足$t$天后恰好能制作$m$束花,那么$t$天之后的每一天都能制作$m$束花,而$t$天之前则不能,满足二分的性质
- 显然枚举答案的边界分别为数组中对应天数的最小值和最大值。因为等待天数小于最小值则一朵花都没开,一定不能制作;而大于最大值则所有花都盛开,一定是能制作出$m$束花的
- 每次二分天数时,判断当前等待天数下计算出的最大能制作出的花束是否大于等于$m$
时间复杂度
二分答案的时间复杂度为$O(log(n))$,每次检查是否满足都要扫描一遍数组,时间复杂度为$O(n)$,因此总时间复杂度为$O(nlog(n))$
C++ 代码
class Solution {
public:
int minDays(vector<int>& bloomDay, int m, int k) {
if (m > bloomDay.size() / k) return -1;
int l = INT_MAX, r = INT_MIN;
for (auto b : bloomDay) {
l = min(l, b);
r = max(r, b);
}
while (l < r) {
int mid = l + (r - l) / 2;
if (check(bloomDay, m, k, mid)) r = mid;
else l = mid + 1;
}
return l;
}
bool check(vector<int> &bd, int m, int k, int target) {
int len = 0, cnt = 0;
for (int i = 0; i < bd.size(); i ++ ) {
if (bd[i] <= target) {
len ++ ;
if (len == k) {
cnt ++ ;
len = 0;
}
} else len = 0;
}
return cnt >= m;
}
};