leetcode1482. 制作 m 束花所需的最少天数

给你一个整数数组 bloomDay,以及两个整数 mk

现需要制作 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

结果:

python 输入总秒数 返回年月日 python输入月份返回天数_二分法