leetcode1482. 制作 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
方法:二分查找
思路:
本题我们采用二分查找的方法,但是比较特殊的是,我们针对天数进行二分查找,因为这里有一个隐含的条件,随着天数的增加,开花的数量也是递增的,而花开的越多,越可能满足条件,所以我们对天数进行二分查找,找到第一个满足条件的天数。
我们考虑二分查找的左右初始值,简单的想法是left=1,right=10^9,然后开始。但是由于答案天数一定是出现在bloomDay中的天数,这样可能会导致一些重复的无意义的运算,所以我们将bloomDay转化为集合去除重复元素,然后转换为列表再排序,组成Days列表,对Days列表开始进行二分查找。
每次查找的时候,我们需要判断这个天数是否符合条件,我们定义isans方法来判断。在isans中,遍历bloomDay,判断这朵花当前有没有开,同时开始计数;遍历结束后判断是否有大于等于m个,不重叠的连续k个开花的子数组,如果有,则符合条件,返回True,否则返回False。
二分结束之后,我们判断此时的天数是不是满足条件,满足返回这个天数,不满足则返回-1。
复杂度分析:
- n朵花,刚开始排序时间复杂度为O(NlogN),之后二分查找复杂度为O(logm),m为days长度,每次处理,遍历一次列表,O(N),总体的渐进时间复杂度为O(Nlogm/NlogN),取决于m和N的大小关系。
- 使用了一个days列表,空间复杂度为O(M)。
代码:
class Solution:
#判断第day天能否成功制作m束花,返回True或False
def isans(self,day,n,bloomDay,m,k):
#temp存放当前连续开花的个数
temp = 0
#bunch表示当前制作成的花束数
bunch = 0
for flower in bloomDay:
#判断这朵花现在开没开
if flower <= day:
if temp == k:
bunch += 1
temp = 0
temp += 1
else:
if temp == k:
bunch += 1
temp = 0
#考虑到最后正好k朵连续的情况
if temp == k:
bunch += 1
return True if bunch >= m else False
def minDays(self, bloomDay: List[int], m: int, k: int) -> int:
n = len(bloomDay)
#花朵总数不够,返回-1
if n < m*k:
return -1
#将可能出现的天数转换为set去重,再转化为列表进行排序
days = list(set(bloomDay))
days.sort()
day_n = len(days)
#开始二分,找到最小的满足条件的天数
left = 0
right = day_n-1
while left < right:
mid = left + (right-left)//2
if self.isans(days[mid],n,bloomDay,m,k):
right = mid
else:
left = mid+1
#如果找到了,即为这个天数,如果没找到,则返回-1
if self.isans(days[left],n,bloomDay,m,k):
return days[left]
else:
return -1
结果: