1482. Minimum Number of Days to Make m Bouquets
Problem Description
You have a garden with n
flowers arranged in a row. Each flower blooms on a specific day given by the array bloomDay
, where bloomDay[i]
represents the day when the i
-th flower will bloom.
Your goal is to make m
bouquets, where each bouquet requires exactly k
adjacent flowers that have already bloomed. Once a flower is used in a bouquet, it cannot be used in another bouquet.
The problem asks you to find the minimum number of days you need to wait before you can make m
bouquets. If it's impossible to make m
bouquets (for example, if there aren't enough flowers total, i.e., n < m * k
), return -1
.
Key constraints:
- Flowers must be adjacent (consecutive) in the garden to form a bouquet
- Each flower can only be used in one bouquet
- A flower can only be used after it has bloomed (on or after day
bloomDay[i]
)
Example scenario:
If bloomDay = [1, 10, 3, 10, 2]
, m = 3
, and k = 1
:
- On day 1: flower at index 0 blooms
- On day 2: flowers at indices 0 and 4 have bloomed
- On day 3: flowers at indices 0, 2, and 4 have bloomed (3 flowers total, can make 3 bouquets of size 1)
- Answer: 3 days
If bloomDay = [1, 10, 3, 10, 2]
, m = 3
, and k = 2
:
- We need 3 bouquets with 2 adjacent flowers each (6 flowers total)
- We only have 5 flowers, so it's impossible
- Answer: -1
Intuition
The key insight is recognizing that this problem has a monotonic property: if we can make m
bouquets by day t
, then we can definitely make m
bouquets on any day after t
(since more flowers will have bloomed). Conversely, if we cannot make m
bouquets by day t
, we cannot make them on any day before t
either.
This monotonic property immediately suggests binary search on the answer. Instead of checking every possible day sequentially, we can search for the minimum day efficiently.
Think of it this way: imagine we have a timeline from day 1 to the maximum bloom day. At some point on this timeline, we transition from "cannot make m
bouquets" to "can make m
bouquets". We want to find that exact transition point.
For any given day d
, we can check if it's possible to make m
bouquets by:
- Looking at which flowers have bloomed by day
d
(those withbloomDay[i] <= d
) - Counting how many groups of
k
consecutive bloomed flowers we can find - Checking if we have at least
m
such groups
The checking process works like a sliding window: we traverse the array and count consecutive bloomed flowers. When we reach k
consecutive bloomed flowers, we've found one bouquet and reset our counter. If we encounter a flower that hasn't bloomed yet, we reset the counter since the consecutive sequence is broken.
The search space for our binary search is from day 1 to the maximum value in bloomDay
(since all flowers will have bloomed by then). We use binary search to efficiently find the smallest day where check(day)
returns true, which gives us our answer in O(n * log(max(bloomDay)))
time instead of O(n * max(bloomDay))
if we checked every day.
Learn more about Binary Search patterns.
Solution Approach
The solution implements binary search to find the minimum number of days needed to make m
bouquets.
Binary Search Setup:
We first determine the search space. The maximum possible answer is the maximum value in bloomDay
array (when all flowers have bloomed), so we set mx = max(bloomDay)
. The search range is from 0 to mx + 1
.
Check Function:
The check(days)
function determines if we can make at least m
bouquets by a given day:
- Initialize
cnt
(bouquet counter) andcur
(current consecutive flowers) to 0 - Iterate through each flower in
bloomDay
:- If
bloomDay[i] <= days
, the flower has bloomed, so incrementcur
by 1 - Otherwise, reset
cur
to 0 (break in consecutive sequence) - When
cur == k
, we've found a complete bouquet:- Increment
cnt
by 1 - Reset
cur
to 0 to start counting the next bouquet
- Increment
- If
- Return
True
ifcnt >= m
, otherwiseFalse
Binary Search Execution:
The code uses Python's bisect_left
function with a clever trick:
l = bisect_left(range(mx + 2), True, key=check)
This searches for the leftmost position where check
returns True
in the range [0, mx + 1]
. The key=check
parameter transforms each value in the range using the check
function, essentially creating a boolean array like [False, False, ..., False, True, True, ..., True]
, and bisect_left
finds the first True
.
Final Result:
- If
l > mx
, it means we couldn't find any valid day within the maximum bloom day, so return-1
- Otherwise, return
l
as the minimum number of days
Time Complexity: O(n * log(max(bloomDay)))
where n
is the length of the array. We perform binary search over the range of days (log(max(bloomDay))
), and for each mid-point, we check if it's valid in O(n)
time.
Space Complexity: O(1)
as we only use a constant amount of extra space.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to illustrate the solution approach.
Example: bloomDay = [7, 7, 7, 7, 12, 7, 7]
, m = 2
, k = 3
We need to make 2 bouquets, each requiring 3 adjacent flowers.
Step 1: Set up binary search range
- Maximum bloom day:
mx = 12
- Search range:
[0, 13)
(0 to 12 inclusive)
Step 2: Binary search process
First iteration: mid = 6
- Check if we can make 2 bouquets by day 6:
- Bloomed status:
[No, No, No, No, No, No, No]
(all flowers bloom on day 7 or 12) - Consecutive count: Can't form any bouquets
- Result:
False
, search right half
Second iteration: mid = 9
- Check if we can make 2 bouquets by day 9:
- Bloomed status:
[Yes, Yes, Yes, Yes, No, Yes, Yes]
(flower at index 4 blooms on day 12) - Traverse array:
- Indices 0-3: 4 consecutive bloomed flowers → make 1 bouquet from indices 0-2, reset counter
- Index 3: 1 consecutive flower
- Index 4: Not bloomed, reset counter
- Indices 5-6: 2 consecutive flowers (not enough for a bouquet)
- Total bouquets: 1
- Result:
False
, search right half
Third iteration: mid = 11
- Check if we can make 2 bouquets by day 11:
- Same as day 9 (flower at index 4 still hasn't bloomed)
- Result:
False
, search right half
Fourth iteration: mid = 12
- Check if we can make 2 bouquets by day 12:
- Bloomed status:
[Yes, Yes, Yes, Yes, Yes, Yes, Yes]
(all flowers have bloomed) - Traverse array:
- Indices 0-2: 3 consecutive flowers → bouquet #1, reset counter
- Indices 3-5: 3 consecutive flowers → bouquet #2, reset counter
- Index 6: 1 flower (leftover)
- Total bouquets: 2
- Result:
True
, this is our answer
Step 3: Return result The minimum day is 12. We need to wait 12 days to make 2 bouquets of 3 adjacent flowers each.
The binary search efficiently found that day 12 is the first day when we can make the required bouquets, avoiding the need to check every single day from 1 to 12.
Solution Implementation
1class Solution:
2 def minDays(self, bloomDay: List[int], m: int, k: int) -> int:
3 """
4 Find the minimum number of days to wait to make m bouquets from the garden.
5 Each bouquet requires k adjacent flowers to bloom.
6
7 Args:
8 bloomDay: List where bloomDay[i] is the day when the i-th flower blooms
9 m: Number of bouquets needed
10 k: Number of adjacent flowers needed for each bouquet
11
12 Returns:
13 Minimum number of days to wait, or -1 if impossible
14 """
15
16 # Early termination: impossible if we don't have enough flowers
17 if m * k > len(bloomDay):
18 return -1
19
20 def can_make_bouquets(days: int) -> bool:
21 """
22 Check if we can make m bouquets after waiting 'days' days.
23
24 Args:
25 days: Number of days to wait
26
27 Returns:
28 True if we can make at least m bouquets, False otherwise
29 """
30 bouquets_made = 0
31 consecutive_bloomed = 0
32
33 # Iterate through each flower position
34 for bloom_day in bloomDay:
35 if bloom_day <= days:
36 # This flower has bloomed by 'days'
37 consecutive_bloomed += 1
38
39 # Check if we have enough consecutive flowers for a bouquet
40 if consecutive_bloomed == k:
41 bouquets_made += 1
42 consecutive_bloomed = 0 # Reset for next bouquet
43 else:
44 # This flower hasn't bloomed yet, break the consecutive chain
45 consecutive_bloomed = 0
46
47 return bouquets_made >= m
48
49 # Binary search for the minimum days
50 # Search range: from minimum bloom day to maximum bloom day
51 left, right = min(bloomDay), max(bloomDay)
52
53 while left < right:
54 mid = (left + right) // 2
55
56 if can_make_bouquets(mid):
57 # We can make enough bouquets, try fewer days
58 right = mid
59 else:
60 # We cannot make enough bouquets, need more days
61 left = mid + 1
62
63 return left
64
1class Solution {
2 // Instance variables to store problem parameters
3 private int[] bloomDay;
4 private int requiredBouquets;
5 private int flowersPerBouquet;
6
7 /**
8 * Finds the minimum number of days to wait for making m bouquets from the garden
9 * @param bloomDay Array where bloomDay[i] is the day when the i-th flower blooms
10 * @param m Number of bouquets needed
11 * @param k Number of adjacent flowers needed for one bouquet
12 * @return Minimum days to wait, or -1 if impossible
13 */
14 public int minDays(int[] bloomDay, int m, int k) {
15 // Store parameters as instance variables for use in helper method
16 this.bloomDay = bloomDay;
17 this.requiredBouquets = m;
18 this.flowersPerBouquet = k;
19
20 // Maximum possible days (upper bound for binary search)
21 final int MAX_DAYS = (int) 1e9;
22
23 // Binary search range: [left, right)
24 int left = 1;
25 int right = MAX_DAYS + 1;
26
27 // Binary search to find minimum days
28 while (left < right) {
29 int mid = (left + right) >> 1; // Equivalent to (left + right) / 2
30
31 if (canMakeBouquets(mid)) {
32 // If we can make required bouquets in 'mid' days, try fewer days
33 right = mid;
34 } else {
35 // If we cannot make required bouquets, we need more days
36 left = mid + 1;
37 }
38 }
39
40 // If left exceeds MAX_DAYS, it's impossible to make required bouquets
41 return left > MAX_DAYS ? -1 : left;
42 }
43
44 /**
45 * Checks if we can make the required number of bouquets within given days
46 * @param days Number of days to wait
47 * @return true if we can make at least m bouquets, false otherwise
48 */
49 private boolean canMakeBouquets(int days) {
50 int bouquetCount = 0; // Number of bouquets we can make
51 int consecutiveFlowers = 0; // Current count of consecutive bloomed flowers
52
53 // Iterate through each flower in the garden
54 for (int bloomTime : bloomDay) {
55 if (bloomTime <= days) {
56 // Flower has bloomed, increment consecutive count
57 consecutiveFlowers++;
58 } else {
59 // Flower hasn't bloomed, reset consecutive count
60 consecutiveFlowers = 0;
61 }
62
63 // Check if we have enough consecutive flowers for a bouquet
64 if (consecutiveFlowers == flowersPerBouquet) {
65 bouquetCount++;
66 consecutiveFlowers = 0; // Reset for next bouquet
67 }
68 }
69
70 // Check if we have made enough bouquets
71 return bouquetCount >= requiredBouquets;
72 }
73}
74
1class Solution {
2public:
3 int minDays(vector<int>& bloomDay, int m, int k) {
4 // Find the maximum bloom day (latest day any flower blooms)
5 int maxDay = ranges::max(bloomDay);
6
7 // Binary search range: [1, maxDay + 1)
8 // left is inclusive, right is exclusive
9 int left = 1, right = maxDay + 1;
10
11 // Lambda function to check if we can make m bouquets by day 'days'
12 auto canMakeBouquets = [&](int days) {
13 int bouquetCount = 0; // Number of bouquets we can make
14 int consecutiveFlowers = 0; // Current consecutive bloomed flowers
15
16 // Iterate through each flower's bloom day
17 for (int bloomDayOfFlower : bloomDay) {
18 if (bloomDayOfFlower <= days) {
19 // Flower has bloomed by 'days', increment consecutive count
20 consecutiveFlowers++;
21 } else {
22 // Flower hasn't bloomed, reset consecutive count
23 consecutiveFlowers = 0;
24 }
25
26 // If we have k consecutive bloomed flowers, make a bouquet
27 if (consecutiveFlowers == k) {
28 bouquetCount++;
29 consecutiveFlowers = 0; // Reset for next bouquet
30 }
31 }
32
33 // Check if we can make at least m bouquets
34 return bouquetCount >= m;
35 };
36
37 // Binary search for the minimum days needed
38 while (left < right) {
39 int mid = (left + right) >> 1; // Equivalent to (left + right) / 2
40
41 if (canMakeBouquets(mid)) {
42 // Can make bouquets by day 'mid', try earlier days
43 right = mid;
44 } else {
45 // Cannot make bouquets by day 'mid', need more days
46 left = mid + 1;
47 }
48 }
49
50 // If left > maxDay, it means we cannot make m bouquets
51 // (happens when m * k > bloomDay.size())
52 return left > maxDay ? -1 : left;
53 }
54};
55
1/**
2 * Finds the minimum number of days to wait for m bouquets with k adjacent flowers each
3 * @param bloomDay - Array where bloomDay[i] is the day the i-th flower blooms
4 * @param m - Number of bouquets needed
5 * @param k - Number of adjacent flowers needed per bouquet
6 * @returns Minimum days to wait, or -1 if impossible
7 */
8function minDays(bloomDay: number[], m: number, k: number): number {
9 // Find the maximum bloom day (latest blooming flower)
10 const maxBloomDay: number = Math.max(...bloomDay);
11
12 // Binary search boundaries: minimum 1 day, maximum is maxBloomDay + 1
13 let left: number = 1;
14 let right: number = maxBloomDay + 1;
15
16 /**
17 * Checks if we can make m bouquets within the given number of days
18 * @param days - Number of days to wait
19 * @returns True if m bouquets can be made, false otherwise
20 */
21 const canMakeBouquets = (days: number): boolean => {
22 let bouquetCount: number = 0; // Number of complete bouquets made
23 let consecutiveFlowers: number = 0; // Current consecutive bloomed flowers
24
25 // Iterate through each flower position
26 for (const bloomTime of bloomDay) {
27 if (bloomTime <= days) {
28 // Flower has bloomed, increment consecutive count
29 consecutiveFlowers++;
30 } else {
31 // Flower hasn't bloomed, reset consecutive count
32 consecutiveFlowers = 0;
33 }
34
35 // Check if we have enough consecutive flowers for a bouquet
36 if (consecutiveFlowers === k) {
37 bouquetCount++;
38 consecutiveFlowers = 0; // Reset for next bouquet
39 }
40 }
41
42 // Return true if we have enough bouquets
43 return bouquetCount >= m;
44 };
45
46 // Binary search for minimum days
47 while (left < right) {
48 const mid: number = (left + right) >> 1; // Equivalent to Math.floor((left + right) / 2)
49
50 if (canMakeBouquets(mid)) {
51 // Can make bouquets in 'mid' days, try fewer days
52 right = mid;
53 } else {
54 // Cannot make bouquets in 'mid' days, need more days
55 left = mid + 1;
56 }
57 }
58
59 // If left exceeds maxBloomDay, it's impossible to make m bouquets
60 return left > maxBloomDay ? -1 : left;
61}
62
Time and Space Complexity
The time complexity is O(n × log M)
, where n
is the length of the bloomDay
array (number of flowers) and M
is the maximum value in bloomDay
(maximum blooming day).
Breaking down the analysis:
- The
bisect_left
function performs binary search on the range[0, mx + 1]
, which takesO(log M)
iterations - For each binary search iteration, the
check
function is called as the key function - The
check
function iterates through alln
elements inbloomDay
, takingO(n)
time - Therefore, the total time complexity is
O(n × log M)
The space complexity is O(1)
as the algorithm only uses a constant amount of extra space for variables like cnt
, cur
, l
, and mx
, regardless of the input size.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding Adjacent Flower Requirement
A common mistake is thinking that any k
flowers that have bloomed can form a bouquet, rather than requiring them to be consecutive/adjacent in the garden.
Incorrect approach:
def can_make_bouquets_wrong(days: int) -> bool:
# WRONG: Just counting total bloomed flowers
bloomed_count = sum(1 for d in bloomDay if d <= days)
return bloomed_count >= m * k
Correct approach: Track consecutive bloomed flowers and reset the counter when encountering an unbloomed flower or after forming a bouquet.
2. Not Resetting Counter After Making a Bouquet
Forgetting to reset the consecutive flower counter after successfully forming a bouquet leads to overcounting.
Incorrect implementation:
def can_make_bouquets_wrong(days: int) -> bool:
bouquets_made = 0
consecutive_bloomed = 0
for bloom_day in bloomDay:
if bloom_day <= days:
consecutive_bloomed += 1
if consecutive_bloomed == k:
bouquets_made += 1
# WRONG: Forgot to reset consecutive_bloomed!
else:
consecutive_bloomed = 0
return bouquets_made >= m
Solution:
Always reset consecutive_bloomed = 0
after incrementing bouquets_made
.
3. Off-by-One Error in Binary Search Bounds
Setting incorrect initial bounds for binary search can miss edge cases.
Common mistakes:
- Starting
left = 0
when the minimum should bemin(bloomDay)
(no flowers bloom before the earliest bloom day) - Using
left <= right
with incorrect mid calculation, causing infinite loops
Correct implementation:
left, right = min(bloomDay), max(bloomDay)
while left < right:
mid = (left + right) // 2
if can_make_bouquets(mid):
right = mid # Include mid as potential answer
else:
left = mid + 1
4. Integer Overflow in Early Termination Check
In languages with fixed integer sizes, m * k
might overflow for large values.
Prevention:
Check using division instead: if m > len(bloomDay) // k:
(with additional logic for when k = 0).
5. Not Handling Edge Cases
Forgetting to check if it's mathematically impossible to create the required bouquets.
Essential check:
if m * k > len(bloomDay):
return -1
This should be done before the binary search to avoid unnecessary computation.
Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?
Recommended Readings
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!