Facebook Pixel

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
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. Looking at which flowers have bloomed by day d (those with bloomDay[i] <= d)
  2. Counting how many groups of k consecutive bloomed flowers we can find
  3. 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 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 feasible(days: int) -> bool:
21            """
22            Check if we can make m bouquets after waiting 'days' days.
23            Returns True if we can make at least m bouquets.
24            """
25            bouquets_made = 0
26            consecutive_bloomed = 0
27
28            for bloom_day in bloomDay:
29                if bloom_day <= days:
30                    consecutive_bloomed += 1
31                    if consecutive_bloomed == k:
32                        bouquets_made += 1
33                        consecutive_bloomed = 0
34                else:
35                    consecutive_bloomed = 0
36
37            return bouquets_made >= m
38
39        # Binary search using the template pattern
40        left, right = min(bloomDay), max(bloomDay)
41        first_true_index = -1
42
43        while left <= right:
44            mid = (left + right) // 2
45
46            if feasible(mid):
47                first_true_index = mid
48                right = mid - 1  # Search for earlier day
49            else:
50                left = mid + 1
51
52        return first_true_index
53
1class Solution {
2    private int[] bloomDay;
3    private int requiredBouquets;
4    private int flowersPerBouquet;
5
6    /**
7     * Finds the minimum number of days to wait for making m bouquets from the garden
8     * @param bloomDay Array where bloomDay[i] is the day when the i-th flower blooms
9     * @param m Number of bouquets needed
10     * @param k Number of adjacent flowers needed for one bouquet
11     * @return Minimum days to wait, or -1 if impossible
12     */
13    public int minDays(int[] bloomDay, int m, int k) {
14        this.bloomDay = bloomDay;
15        this.requiredBouquets = m;
16        this.flowersPerBouquet = k;
17
18        // Early termination: impossible if we don't have enough flowers
19        if ((long) m * k > bloomDay.length) {
20            return -1;
21        }
22
23        // Find min and max bloom days for search bounds
24        int minDay = Integer.MAX_VALUE;
25        int maxDay = Integer.MIN_VALUE;
26        for (int day : bloomDay) {
27            minDay = Math.min(minDay, day);
28            maxDay = Math.max(maxDay, day);
29        }
30
31        // Binary search using the template pattern
32        int left = minDay;
33        int right = maxDay;
34        int firstTrueIndex = -1;
35
36        while (left <= right) {
37            int mid = left + (right - left) / 2;
38
39            if (feasible(mid)) {
40                firstTrueIndex = mid;
41                right = mid - 1;  // Search for earlier day
42            } else {
43                left = mid + 1;
44            }
45        }
46
47        return firstTrueIndex;
48    }
49
50    /**
51     * Checks if we can make the required number of bouquets within given days
52     * @param days Number of days to wait
53     * @return true if we can make at least m bouquets, false otherwise
54     */
55    private boolean feasible(int days) {
56        int bouquetCount = 0;
57        int consecutiveFlowers = 0;
58
59        for (int bloomTime : bloomDay) {
60            if (bloomTime <= days) {
61                consecutiveFlowers++;
62                if (consecutiveFlowers == flowersPerBouquet) {
63                    bouquetCount++;
64                    consecutiveFlowers = 0;
65                }
66            } else {
67                consecutiveFlowers = 0;
68            }
69        }
70
71        return bouquetCount >= requiredBouquets;
72    }
73}
74
1class Solution {
2public:
3    int minDays(vector<int>& bloomDay, int m, int k) {
4        // Early termination: impossible if we don't have enough flowers
5        if ((long long) m * k > bloomDay.size()) {
6            return -1;
7        }
8
9        // Find min and max bloom days for search bounds
10        int minDay = ranges::min(bloomDay);
11        int maxDay = ranges::max(bloomDay);
12
13        // Lambda function to check if we can make m bouquets by day 'days'
14        auto feasible = [&](int days) {
15            int bouquetCount = 0;
16            int consecutiveFlowers = 0;
17
18            for (int bloomDayOfFlower : bloomDay) {
19                if (bloomDayOfFlower <= days) {
20                    consecutiveFlowers++;
21                    if (consecutiveFlowers == k) {
22                        bouquetCount++;
23                        consecutiveFlowers = 0;
24                    }
25                } else {
26                    consecutiveFlowers = 0;
27                }
28            }
29
30            return bouquetCount >= m;
31        };
32
33        // Binary search using the template pattern
34        int left = minDay;
35        int right = maxDay;
36        int firstTrueIndex = -1;
37
38        while (left <= right) {
39            int mid = left + (right - left) / 2;
40
41            if (feasible(mid)) {
42                firstTrueIndex = mid;
43                right = mid - 1;  // Search for earlier day
44            } else {
45                left = mid + 1;
46            }
47        }
48
49        return firstTrueIndex;
50    }
51};
52
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    // Early termination: impossible if we don't have enough flowers
10    if (m * k > bloomDay.length) {
11        return -1;
12    }
13
14    // Find min and max bloom days for search bounds
15    const minBloomDay: number = Math.min(...bloomDay);
16    const maxBloomDay: number = Math.max(...bloomDay);
17
18    /**
19     * Checks if we can make m bouquets within the given number of days
20     * @param days - Number of days to wait
21     * @returns True if m bouquets can be made, false otherwise
22     */
23    const feasible = (days: number): boolean => {
24        let bouquetCount: number = 0;
25        let consecutiveFlowers: number = 0;
26
27        for (const bloomTime of bloomDay) {
28            if (bloomTime <= days) {
29                consecutiveFlowers++;
30                if (consecutiveFlowers === k) {
31                    bouquetCount++;
32                    consecutiveFlowers = 0;
33                }
34            } else {
35                consecutiveFlowers = 0;
36            }
37        }
38
39        return bouquetCount >= m;
40    };
41
42    // Binary search using the template pattern
43    let left: number = minBloomDay;
44    let right: number = maxBloomDay;
45    let firstTrueIndex: number = -1;
46
47    while (left <= right) {
48        const mid: number = Math.floor((left + right) / 2);
49
50        if (feasible(mid)) {
51            firstTrueIndex = mid;
52            right = mid - 1;  // Search for earlier day
53        } else {
54            left = mid + 1;
55        }
56    }
57
58    return firstTrueIndex;
59}
60

Solution Approach

The solution implements binary search to find the minimum number of days needed to make m bouquets.

Early Termination: Before starting the binary search, we check if it's even possible to make m bouquets. If m * k > len(bloomDay), there aren't enough flowers, so we return -1 immediately.

Feasible Function: The feasible(days) function determines if we can make at least m bouquets by a given day:

  • Initialize bouquetCount and consecutiveFlowers to 0
  • Iterate through each flower in bloomDay:
    • If bloomDay[i] <= days, the flower has bloomed, so increment consecutiveFlowers
    • Otherwise, reset consecutiveFlowers to 0 (break in consecutive sequence)
    • When consecutiveFlowers == k, we've found a complete bouquet:
      • Increment bouquetCount by 1
      • Reset consecutiveFlowers to 0 to start counting the next bouquet
  • Return True if bouquetCount >= m, otherwise False

Binary Search Template: We use the standard binary search template to find the first day where feasible(day) returns True:

left, right = min(bloomDay), max(bloomDay)
first_true_index = -1

while left <= right:
    mid = (left + right) // 2
    if feasible(mid):
        first_true_index = mid
        right = mid - 1  # Search for earlier day
    else:
        left = mid + 1

return first_true_index

The key insight is that the feasibility forms a monotonic pattern: [False, False, ..., False, True, True, ..., True]. Once we can make m bouquets on day d, we can always make them on any later day. We track first_true_index to remember the earliest valid day found, and use right = mid - 1 to continue searching for an even earlier day.

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 Evaluator

Example 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: Initialize binary search

  • left = min(bloomDay) = 7
  • right = max(bloomDay) = 12
  • first_true_index = -1

Step 2: Binary search process (while left <= right)

Iteration 1: left = 7, right = 12, mid = 9

  • Check feasible(9):
  • Bloomed status: [Yes, Yes, Yes, Yes, No, Yes, Yes] (flower at index 4 blooms on day 12)
  • Traverse array:
    • Indices 0-2: 3 consecutive flowers → bouquet #1, reset counter
    • Index 3: 1 consecutive flower
    • Index 4: Not bloomed, reset counter
    • Indices 5-6: 2 consecutive flowers (not enough)
  • Total bouquets: 1, need 2
  • Result: False, set left = mid + 1 = 10

Iteration 2: left = 10, right = 12, mid = 11

  • Check feasible(11):
  • Same as day 9 (flower at index 4 still hasn't bloomed on day 11)
  • Total bouquets: 1
  • Result: False, set left = mid + 1 = 12

Iteration 3: left = 12, right = 12, mid = 12

  • Check feasible(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, set first_true_index = 12, right = mid - 1 = 11

Iteration 4: left = 12, right = 11

  • left > right, exit loop

Step 3: Return result Return first_true_index = 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 7 to 12.

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 takes O(log M) iterations
  • For each binary search iteration, the check function is called as the key function
  • The check function iterates through all n elements in bloomDay, taking O(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. Using Wrong Binary Search Template Variant

A common mistake is using the while left < right with right = mid variant instead of the standard template with first_true_index tracking.

Incorrect approach:

# WRONG: Different template variant
while left < right:
    mid = (left + right) // 2
    if feasible(mid):
        right = mid
    else:
        left = mid + 1
return left

Correct approach: Use the standard template with first_true_index to track the answer:

first_true_index = -1
while left <= right:
    mid = (left + right) // 2
    if feasible(mid):
        first_true_index = mid
        right = mid - 1
    else:
        left = mid + 1
return first_true_index

2. 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 feasible_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.

3. 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 feasible_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.

4. Integer Overflow in Early Termination Check

In languages with fixed integer sizes, m * k might overflow for large values.

Prevention: Cast to long before multiplication: if (long) m * k > bloomDay.length.

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.

Loading...
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".

What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More