- 制作 m 束花所需的最少天数
给你一个整数数组 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
示例 2:
输入:bloomDay = [1,10,3,10,2], m = 3, k = 2
输出:-1
解释:要制作 3 束花,每束需要 2 朵花,也就是一共需要 6 朵花。而花园中只有 5 朵花,无法满足制作要求,返回 -1 。
示例 3:
输入: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]
显然,我们可以用不同的方式制作两束花。
示例 4:
输入:bloomDay = [1000000000,1000000000], m = 1, k = 1
输出:1000000000
解释:需要等 1000000000 天才能采到花来制作花束
示例 5:
输入:bloomDay = [1,10,2,9,3,8,4,7,5,6], m = 4, k = 2
输出:9
提示:
bloomDay.length == n
1 <= n <= 10^5
1 <= bloomDay[i] <= 10^9
1 <= m <= 10^6
1 <= k <= n
每束花需要 k 朵花,需要制作 m 束花,因此一共需要 k×m 朵花。如果花园中的花朵数量少于k×m,即数组 bloomDay 的长度小于 k×m,则无法制作出指定数量的花束,返回 −1。如果数组 bloomDay 的长度大于或等于 k×m,则一定可以制作出指定数量的花束。
为了计算制作出指定数量的花束的最少天数,首先需要实现一个辅助函数用于判断在给定的天数内能否制作出指定数量的花束,辅助函数的参数除了 bloomDay、m 和 k 之外,还有一个参数 days 表示指定天数。例如,当bloomDay=[1,10,3,10,2]、m=3、k=1 时,如果 days=3 则辅助函数返回 true,如果 days=2 则辅助函数返回false。
对于辅助函数的实现,可以遍历数组 bloomDay,计算其中的长度为 kk 且最大元素不超过 days 的不重合的连续子数组的数量,如果符合要求的不重合的连续子数组的数量大于或等于 m 则返回 true,否则返回false。
当 days 很小的时候,辅助函数总是返回 false,因为天数太少不能收齐 m 个花束;当 days 很大的时候,辅助函数总是返回 true,如果给定序列可以制作出 m 个花束。在 days 慢慢变大的过程中,辅助函数的返回值会从 false 变成 true,所以我们可以认为这个辅助函数是关于 days 递增的,于是可以通过二分查找得到最少天数。在确保可以制作出指定数量的花束的情况下,所需的最少天数一定不会超过数组 bloomDay 中的最大值,因此二分查找的初始值是 low 等于 1,high 等于数组 bloomDay 中的最大值。
当 low 和 high 的值相等时,二分查找结束,此时 low 的值即为最少天数。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/minimum-number-of-days-to-make-m-bouquets/solution/zhi-zuo-m-shu-hua-suo-xu-de-zui-shao-tia-mxci/
读完题目你会发现:
制作花朵最少的时间必然是 bloomDay 数组中开花所用天数最少的那朵花 min(bloomDay)
制作花朵最多的时间也只能是 bloomDay 数组中开花所需天数最多的那朵花 max(bloomDay)
寻找制作花束的最少天数必然落在上面所说的区间里 [min(bloomDay), max(bloomDay)][min(bloomDay),max(bloomDay)], 连续的一个正整数区间, 因此可以通过二分查找来提升查找效率!
这就是拿到这个题目的一些大致思考方向.
细节处理
除此之外, 还有一些细节来填充, 代码就算有一个完整的雏形了.
数组中的花朵不够用来制作花束的, 直接返回 -1
必须是连续的花朵, 这个可以通过变量 flower 来计数是否连续, 一旦不连续就重置为 0
每满足一次连续的 k 朵花, 就可以制作一束花, flower 计数重新为 0 开始计数
作者:niconiconi-12
链接:https://leetcode-cn.com/problems/minimum-number-of-days-to-make-m-bouquets/solution/chi-xiao-dou-python-wei-shi-yao-shi-er-f-24p7/
class Solution {
public:
int minDays(vector<int>& bloomDay, int m, int k) {
if (bloomDay.size() < m * k) return -1;
int low = 1, high = 1, len = bloomDay.size();
for (int i = 0; i < len; ++i) {
if(bloomDay[i] > high) high = bloomDay[i];
}
while (low < high) {
int days = (low + high) / 2;
if (makeBundles(bloomDay, days, m, k)) high = days;
else low = days + 1;
}
return low;
}
bool makeBundles(vector<int>& bloomDay, int days, int m, int k) {
int count = 0, flowers = 0, len = bloomDay.size();
for (int i = 0; i < len && count < m; ++i) {
if (bloomDay[i] <= days) {
flowers++;
if (flowers >= k) {
count++;
flowers = 0;
}
}
else flowers = 0;
}
return count >= m;
}
};