持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情
刷题的日常
一天一题,保持脑子清爽
制作 m 束花所需的最少天数
题来自leetcode的1482题,题意如下:
给你一个整数数组 bloomDay,以及两个整数 m 和 k 。
现需要制作 m 束花。制作花束时,需要使用花园中 相邻的 k 朵花 。
花园中有 n 朵花,第 i 朵花会在 bloomDay[i] 时盛开,恰好 可以用于 一束 花中。
请你返回从花园中摘 m 束花需要等待的最少的天数。如果不能摘到 m 束花则返回 -1 。
理解题意
通过对题目的理解,可以将信息整理如下:
- bloomDay是一个数组,存放了每朵花开花所需要的天数
- m是需要制作的数量,要制作一束花,则必须摘k朵相邻的花,所以我们总共需要m * k朵花
- 在满足m * k朵的条件下,要让开花的时间尽可能短
- 返回最短的可以制作m束花的时间
做题思路
解题的步骤如下:
- 首先,如果数组长度不满k * m,那么可以直接返回-1,因为不够数量
- 如果够数量,那么最大天数肯定是可以制作出m束花,我们可以将最大值提取出来
- 有了最大数量,我们就可以从 1到最大天数之间进行判断(假设天数为i),看下i天能否种出k个相邻的m束花
- 暴力枚举显然不行,最大天数可能很大,那么我们可以用二分对天数进行搜索
- 如果当前天数满足条件,那么可以往天数少的地方靠
- 如果不满足,那么就往天数大的一侧靠
- 返回最终结果
代码实现
对最大天数i来说,可能需要判断logi次,判断需要扫描数组,所以时间复杂度为O(nlogi),代码如下:
public class Solution {
public int minDays(int[] bloomDay, int m, int k) {
int total = m * k;
if (total > bloomDay.length) {
return -1;
}
int min = bloomDay[0];
int max = bloomDay[0];
for (int day : bloomDay) {
max = Math.max(day, max);
min = Math.min(day, min);
}
int l = min, r = max, mid;
while (l < r) {
mid = l + (r - l) / 2;
if (check(bloomDay, mid, total, k)) {
r = mid;
continue;
}
l = mid + 1;
}
return l;
}
private boolean check(int[] bloomDay, int selDay, int total, int k) {
int sum = 0;
for (int day : bloomDay) {
if (total <= 0) {
return true;
}
if (selDay < day) {
sum = 0;
continue;
}
if (++sum % k == 0) {
total -= k;
}
}
return total <= 0;
}
}