力扣 1482. 制作 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

来源:力扣(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)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值