力扣 1482. 制作 m 束花所需的最少天数

  • Post author:
  • Post category:其他




题目描述

给你一个整数数组

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

来源:力扣(LeetCode)

链接:

https://leetcode-cn.com/problems/minimum-number-of-days-to-make-m-bouquets


著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。




二分查找:右区找下界

为什么使用二分查找?

  • 对于连续的天数,可以找到一个分界点

    x

    天,小于

    x

    天都无法做成花束,大于等于

    x

    天可以做成花束。
  • 相当于考虑连续的整数区间,小于

    x

    不满足条件,大于等于

    x

    满足条件,很明显可以使用二分查找中的右区找下界模板。当然左区找上界的模板也能使用,只不过没有那么直观。
  • 注意:只要满足花的总数量

    n

    大于等于

    m * k

    则一定可以做出花束。可以在程序开始的地方检验这一条件。
class Solution:
    def minDays(self, bloomDay: List[int], m: int, k: int) -> int:
        n = len(bloomDay)
        # 如果花的个数小于需求总量,返回 -1。
        if n < m * k:
            return -1

        # 随着天数的增加,小于 x 天都无法做成花束,大于等于 x 天都可以做成花束。
        # 所以可以对天数进行二分查找,使用的模板是右区找下界。
        def check(x):
            bouquet = flower = 0
            for i in bloomDay:
                if x >= i:
                    flower += 1
                    if flower >= k:
                        bouquet += 1
                        flower = 0
                else:
                    flower = 0
                if bouquet == m:
                    break
            return bouquet >= m

        def bslb(l, r):
            while l < r:
                m = l + r >> 1
                if check(m):
                    r = m
                else:
                    l = m + 1
            return l
        
        # 遍历一次取得二分查找的左端点和右端点
        l, r = int(1e9), 1
        for i in bloomDay:
            if i < l:
                l = i
            if i > r:
                r = i
        return bslb(l, r)


运行结果

执行结果:通过

执行用时:928 ms, 在所有 Python3 提交中击败了53.75% 的用户

内存消耗:25.3 MB, 在所有 Python3 提交中击败了83.13% 的用户




二分查找模板

二分查找模板之

左区找上界

def check(x):
    pass

def bsub(l, r):
    while l < r:
        m = l + r + 1 >> 1
        if check(m):
            l = m
        else:
            r = m - 1
        return l

l, r = 0, len(nums) - 1
res = bsub(l, r)

二分查找模板之

右区找下界

def check(x):
    pass

def bslb(l, r):
    while l < r:
        m = l + r >> 1
        if check(m):
            r = m
        else:
            l = m + 1
        return l

l, r = 0, len(nums) - 1
res = bslb(l, r)



版权声明:本文为jpch89原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。