1482. 制作 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
解题思路:
本题与力扣 1011. 在 D 天内送达包裹的能力 相似,涉及知识点为二分查找
1、二分左右边界的确定:
左边界:应该是从最小的天数开始 即left=1;
右边界:考虑数组中的最大值是所需最大天数,即right的取值。
2、不同于1011.本题需要连续的k朵花,所以我们还需要对连续满足的数字进行分组
如果 当前数字(代表需要开花的天数)>mid ------即为分割点。将之前满足条件的连续数字以k为大小分组(res+=sum//k),这里的sum统计的是满足条件的连续数字个数。随后将sum置0;
若当前值x<=mid,说明这个数字满足要求,那么统计个数的sum只需要+1;
需要单独讨论最后一个值大于mid的情况
3、移动 left、right的条件:
分组个数res代表组成的花束个数 与 m 比较:
若res>=m 记录当前的等待天数mid, 然后缩小范围 右边界左移
若res < m 不满足条件,增加等待的天数 左边界右移
直接附代码
class Solution {
int minDays(vector<int>& a, int m, int k) {
int len=a.size();
if(len<m*k) return -1;
int ans=0;
int left=1,right=0;
for(int x:a)
right=max(x,right);
while(left<=right)
{
int mid=left+(right-left)/2;
int sum=0,res=0; //sum代表满足要求的连续数字个数 res代表满足要求的分组总数
for(int x:a)
{
if(x>mid) //当前需要的开花的天数大 作为分割点
{
res+=sum/k;
sum=0;
}
else
sum++;
}
res+=sum/k;
if(res>=m) //分组个数满足 缩小范围
{
ans=mid;
right=mid-1;
}
else //不满足增加天数
left=mid+1;
}
return ans;
}
};