《LeetCode之每日一题》:24. 制作 m 束花所需的最少天数

Posted 是七喜呀!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《LeetCode之每日一题》:24. 制作 m 束花所需的最少天数相关的知识,希望对你有一定的参考价值。

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


题目链接: 制作 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 天才能采到花来制作花束
提示:

bloomDay.length == n
1 <= n <= 10^5
1 <= bloomDay[i] <= 10^9
1 <= m <= 10^6
1 <= k <= n

题解

法一:二分查找

思路:
1、判断能够制作花束基本条件
2、找出bloomDay中的最大元素,即所需时间最长的花
3、构造辅助函数canMake--作用:判断在给定的天数内能否制作出指定数量的花束,可以return true;反之false
4、根据二分查找特殊性,逼近所需最小天数

详细见官方链接

class Solution {
public:
    int minDays(vector<int>& bloomDay, int m, int k) {
        if (m > (bloomDay.size() / k))//防止溢出我们用除
            return -1;
        int low = 1, high = 1;
        for (int i = 0; i < bloomDay.size(); i++)
            high = max(high,bloomDay[i]);
        while(low < high)
        {
            
            int days = (high - low) / 2 + low;
            if (canMake(bloomDay,m,k,days))//days随着二分查找的进行从大到小慢慢逼近最少天数,刚开始肯定是能找到某一天数,只不过不是最小而已罢了
                high = days;
            else
                low = days + 1;
//我们low记录的最终目的为逼近最少需要制作花的天数,随着二分查找
        }
        return low;
    }

    bool canMake(vector<int> &bloomDay,int m,int k, int days)
    {
        int flowers = 0;
        int bouquets = 0;//定义花束
        int length = bloomDay.size();
        for (int i = 0; i < length && bouquets < m; i++)
        {
            //这边就是限制连续的子数组,满足就进行
            if (bloomDay[i] <= days)
            {
                flowers++;
                if (flowers == k)
                    {
                        bouquets++;
                        flowers = 0;
                    }
            }
            else //不满足条件就将前面的花朵置零,因为不连续,即不相邻了
            {
                flowers = 0;
            }
        }
        return bouquets >= m;
    }
};

时间复杂度:O(nlogh)

n为数组的的长度,h为数组中最大元素,先遍历找到最大元素,最坏需要O(n)次
接下俩的二分迭代次数,所需O(logh)次,要判断是否可以组成花束所需O(n),因此所需时间复杂度O(nlogh)

结合函数函数的单调性,故总的时间复杂度为O(nlogh)

空间复杂度:O(1)
在这里插入图片描述
C版本

int canMake(int* bloomDay, int bloomDaySize,int m, int k,int days)
{
    int flowers = 0;
    int bouquets = 0;
    int length = bloomDaySize;
    for (int i = 0; i < length && bouquets < m; i++)
    {
        if (bloomDay[i] <= days)
            {
                flowers++;
                if (flowers == k)
                {
                    bouquets++;
                    flowers = 0;
                }
            }
        else
            {
                flowers = 0;
            }
    }
    return bouquets >= m;
}
int minDays(int* bloomDay, int bloomDaySize, int m, int k){
    if (m > (bloomDaySize / k))
        return -1;
    int low = 1, high = 1;
    for (int i = 0; i < bloomDaySize; i++)
    {
        high = fmax(high,bloomDay[i]);
    }
    while (low < high)
    {
        int days = (high - low) / 2 + low;
        if (canMake(bloomDay,bloomDaySize,m,k,days))
            high = days;
        else
            low = days + 1; 
    }
    return low;
}

在这里插入图片描述

以上是关于《LeetCode之每日一题》:24. 制作 m 束花所需的最少天数的主要内容,如果未能解决你的问题,请参考以下文章

《LeetCode之每日一题》:200.

《LeetCode之每日一题》:280.矩阵置零

[每日一题2020.06.17] leetcode周赛T3 5438 制作m束花所需的最少天数 二分搜索

《LeetCode之每日一题》:53.一和零

《LeetCode之每日一题》:18.合并两个有序数组

《LeetCode之每日一题》:163.超级洗衣机