算法--制作花束

73 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

题目

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

给你一个整数数组 bloomDay,以及两个整数 m 和 k 。

现需要制作 m 束花。制作花束时,需要使用花园中 相邻的 k 朵花 。

花园中有 n 朵花,第 i 朵花会在 bloomDay[i] 时盛开,恰好 可以用于 一束 花中。

请你返回从花园中摘 m 束花需要等待的最少的天数。如果不能摘到 m 束花则返回 -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

题解:

这道题是二分的思想。凡是求最大,最小,最大最小,最小最大的题,一般首先想到的应该是用二分的方法,如果不行再用别的方法。

首先二分的下限就是l=0,因为最少就是需要0天,上限就是r=max(boolday[i]),就是让开花时间最长的。那么我们就在(l,r)中寻找答案。对于一个给定的天数limit,我们需要遍历数组,看看存在k个连续的开花的吗,如果是符合,那么limit应该减少,如果不符合,limit增加。直到l=r,这时的l,就是最少的天数。judge函数是判断的方法,就比较简单,昨天的一个题是用的回溯,今天直接遍历就行了。

 var minDays = function(bloomDay, m, k) {
    if (k * m > bloomDay.length) {
        return -1;
    }
    let l = 1, r = Math.max(...bloomDay);
    const length = bloomDay.length;
    while (l < r) {
        const days = Math.floor((r - l) / 2) + l;
        if (canMake(bloomDay, days, m, k)) {
            r = days;
        } else {
            l = days + 1;
        }
    }
    return l;
};

const canMake = (bloomDay, days, m, k) => {
    let bouquets = 0;
    let flowers = 0;
    const length = bloomDay.length;
    for (let i = 0; i < length && bouquets < m; i++) {
        if (bloomDay[i] <= days) {
            flowers++;
            if (flowers == k) {
                bouquets++;
                flowers = 0;
            }
        } else {
            flowers = 0;
        }
    }
    return bouquets >= m;
}

代码详解

定义二分相关的变量l、r,循环遍历判断当天的花和相邻天数的花是否可以摘取。通过辅助函数canMake来判断当天的花束的情况。