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 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) and cur (current consecutive flowers) to 0
  • Iterate through each flower in bloomDay:
    • If bloomDay[i] <= days, the flower has bloomed, so increment cur 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
  • Return True if cnt >= m, otherwise False

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 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: 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 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. 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 be min(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.

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

Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?


Recommended Readings

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

Load More