DSA sheet · Binary Search · Binary search on answer

Minimum Number of Days to Make m Bouquets

Another binary search on answer problem. This time the answer is a number of days to wait. The new ideas the teacher brings in are: a quick base case that tells us right away when it's impossible (not enough flowers in total), the adjacent flowers rule, which forces us to throw away our partly-collected flowers whenever we hit one that hasn't bloomed, and choosing low = min(bloomDay) and high = max(bloomDay). She ends the video with the pattern's two-line summary, which is worth memorising.

Every part below follows the same order:
① the question in simple words → ② what the constraints tell us → ③ intuition → ④ building the logic from examples → ⑤ approach steps → ⑥ code → ⑦ code line by line → ⑧ dry run → ⑨ complexity & remember

Part 0 · Before starting

Why binary search works at all

Binary search only needs a yes/no question that switches once along an ordered set of values: no, no, no, then yes, yes, yes. Such a question is called monotonic. Looking at the middle value tells us which side the switch is on, and we throw away the other side. The values can be an array, or a range of numbers we choose, which is what this pattern does.

low, high, mid

Why mid = low + (high - low) // 2?

Here days go up to 10⁹. In Java/C++, low + high could then reach 2 × 10⁹, which is past the int limit (about 2.1 × 10⁹ is the edge), and it would overflow into a wrong negative number. low + (high - low) / 2 never builds a number bigger than high. Python's ints never overflow, so in Python both forms are fine; we keep the safe one out of habit.

The pattern: binary search on answer

  1. Answer range: the earliest day that could possibly work (low) and a day that surely works if anything does (high).
  2. Check function: check(day) = "if I come on this day, can I make m bouquets?"
  3. Monotonic: a flower that has bloomed stays bloomed. Waiting longer only adds bloomed flowers, never removes any. So once some day works, every later day works too: no no no yes yes yes.
  4. Which side to keep: we want the minimum waiting = the first yes. Yes at mid → save it, go left. No → go right.
days:       low ........................................ high
check(day): no   no   no   no  YES  YES  YES  YES  YES
                               ^
                  the first YES = fewest days to wait
The teacher's summary of the patternBinary search on answer is all about two jobs: (1) find low and high, (2) write the check function. Then: if the question asks for a minimum and mid is possible → go left. If it asks for a maximum and mid is possible → go right.

Part A · Brute force: try every day from min to max

LeetCode 1482

1The question in simple words

A garden has n flowers in a row. bloomDay[i] is the day flower i blooms. You can only pick a flower on or after its bloom day. If a flower says 10 and you come on day 7, 8 or 9, you can't pick it; you have to wait until day 10.

You want m bouquets. Each bouquet needs exactly k flowers that are adjacent (next to each other in the row, with no gap). Each flower can be in only one bouquet. Return the minimum number of days you must wait to be able to make m bouquets, or −1 if it's impossible.

index01234
bloomDay1103102m = 3, k = 1 → answer 3

On day 3, flowers 0 (bloomed day 1), 2 (day 3) and 4 (day 2) are open. k = 1, so each one alone is a bouquet → 3 bouquets ✓. On day 2 only flowers 0 and 4 are open → 2 bouquets, not enough.

Doubt: what does "adjacent" really stop us from doing?
→ Say k = 2 and on some day flowers 0 and 2 are open but flower 1 (between them) isn't. You can't put 0 and 2 in the same bouquet, because they're not next to each other. Each of them could only join a bouquet with its own open neighbours. The teacher shows this with the 1 and the 3 in the array above: they are separated by a 10, so they can never be in one bouquet together.

2What the constraints tell us

3Intuition

The question wants a day. So, as with every problem of this pattern, we guess a day, then walk along the garden and count how many bouquets we could make if we came that day. Try days from the earliest upward; the first day that gives at least m bouquets is the fewest days to wait.

4Building the logic from examples

First: the base case (impossible no matter how long you wait)

The teacher changes the example to m = 3 bouquets of k = 2 flowers. That needs 3 × 2 = 6 flowers, but the garden only has 5. Even if we wait until every flower blooms, there aren't enough flowers. So:

Base caseif m * k > n: return -1
Not enough flowers in total → impossible, no searching needed.
Doubt: if m × k ≤ n, can the answer still be −1?
→ No. On the last bloom day (max of bloomDay) every flower is open, so the whole row is one long run of n adjacent flowers. That gives n // k ≥ m bouquets. So once the base case passes, an answer always exists. The return -1 after the search is just a safety line.

The check: how many bouquets can I make on a given day?

Walk the garden left to right with two counters: count = adjacent open flowers collected so far for the current bouquet, and bouquets = bouquets made.

The teacher walks this on [1, 10, 3, 10, 2], k = 1, day = 1: flower 0 (1 ≤ 1) → count 1 = k → bouquet 1, count 0. Flower 1 (10 > 1) → can't pick, move on. Flower 2 (3 > 1) → no. Flower 3 (10) → no. Flower 4 (2 > 1, it blooms tomorrow) → no. Only 1 bouquet < 3 → day 1 fails, try later days.

Doubt: why is the reset in the "not open" branch so important?
→ Take [7, 7, 7, 7, 12, 7, 7], m = 2, k = 3, day = 7. Walking: 7, 7, 7 → bouquet 1, count 0. Next 7 → count 1. Then 12 is not open. Without the reset, count stays 1, and the next two 7s make count 3 → a second "bouquet" made of flowers 3, 5, 6, which are not adjacent (flower 4 is in between). That would wrongly say day 7 works. With the reset, count goes back to 0 at the 12, the last two 7s only reach count 2 → 1 bouquet → day 7 correctly fails. The real answer is day 12.

Choosing low and high

5Approach steps

  1. If m * k > n → return −1.
  2. low = min(bloomDay), high = max(bloomDay).
  3. For each day d from low to high: if canMake(d) → return d (the first that works is the minimum).
  4. canMake(d): count = 0, bouquets = 0. For each flower: open → count += 1, and if count == k → bouquets += 1, count = 0. Not open → count = 0. Return bouquets ≥ m.
  5. After the loop → return −1 (never reached once the base case passes).

6Code (Python)

Brute force (correct, but TLE)
class Solution:
    def minDays(self, bloomDay, m, k):
        n = len(bloomDay)
        if m * k > n:                       # not enough flowers at all
            return -1
        low = min(bloomDay)                  # nothing opens before this
        high = max(bloomDay)                 # everything is open by now
        for d in range(low, high + 1):
            if self.canMake(bloomDay, m, k, d):
                return d                     # first that works = minimum
        return -1

    def canMake(self, bloomDay, m, k, day):
        count = 0                            # adjacent open flowers in hand
        bouquets = 0
        for bloom in bloomDay:
            if bloom <= day:                 # open: pick it
                count += 1
                if count == k:               # enough for one bouquet
                    bouquets += 1
                    count = 0                # start the next bouquet fresh
            else:                            # not open: chain is broken
                count = 0
        return bouquets >= m

7Code line by line

linewhat it means
if m * k > n: return -1We need m × k flowers but only have n. (Java needs long here: up to 10¹¹.)
low = min(bloomDay) high = max(bloomDay)The answer range: first useful day, and the day when all are open.
for d in range(low, high + 1):Try every day in order.
if self.canMake(...): return dGoing upward, so the first day that works is the least waiting.
if bloom <= day:This flower is open on that day.
count += 1Add it to the bouquet we're building.
if count == k: bouquets += 1 count = 0Bouquet complete. Reset so the next flowers start a new bouquet.
else: count = 0A closed flower breaks adjacency. Flowers before it can't join flowers after it, so drop them.
return bouquets >= mAt least m bouquets → this day works.

8Dry run

bloomDay = [1, 10, 3, 10, 2], m = 3, k = 1. Base case: 3 × 1 = 3 ≤ 5 ✓. low = 1, high = 10.

dayopen flowers (index: bloom)bouquets≥ 3 ?
10:11no
20:1, 4:22no
30:1, 2:3, 4:23yes → return 3
day        :  1    2    3    4    5    6    7    8    9   10
bouquets   :  1    2    3    3    3    3    3    3    3    5
>= 3 ?     :  no   no  YES  YES  YES  YES  YES  YES  YES  YES
                        ^ first YES = 3

9Complexity & remember

Remember the brute forceBase case m × k > n → −1. Days from min to max of bloomDay. Open → count; count == k → bouquet, reset; closed → reset.

Part B · Optimal: binary search on the day

1The question

Same as Part A, same base case, same range, same canMake. As she puts it, nothing else changes: the for loop becomes a while loop with binary search.

2Constraints

The range min … max can be up to 10⁹ long. Halving it takes about log₂(10⁹) ≈ 30 steps.

3Intuition

The days low … high sit on a number line in sorted order, and "can I make m bouquets by this day?" switches from no to yes just once. So rather than walking every day, check the middle day and drop half the line.

4Building the decisions

She moves fast here because this is the same template as the previous problems of this pattern (Koko, Ship Packages, Min Speed). If it feels quick, revisit the first two.

5Approach steps

  1. If m * k > n → −1.
  2. low = min(bloomDay), high = max(bloomDay), ans = -1.
  3. While low ≤ high: mid = low + (high − low) // 2.
  4. canMake(mid) → ans = mid, high = mid − 1. Else → low = mid + 1.
  5. Return ans.

6Code (Python)

Binary search on answer
class Solution:
    def minDays(self, bloomDay, m, k):
        n = len(bloomDay)
        if m * k > n:
            return -1
        low = min(bloomDay)
        high = max(bloomDay)
        ans = -1
        while low <= high:
            mid = low + (high - low) // 2       # mid = the day we test
            if self.canMake(bloomDay, m, k, mid):
                ans = mid                       # possible: remember it
                high = mid - 1                  # try waiting less
            else:
                low = mid + 1                   # not yet: wait longer
        return ans

    def canMake(self, bloomDay, m, k, day):
        count = 0
        bouquets = 0
        for bloom in bloomDay:
            if bloom <= day:
                count += 1
                if count == k:
                    bouquets += 1
                    count = 0
            else:
                count = 0
        return bouquets >= m

7Code line by line

linewhat it means
if m * k > n: return -1Same base case as Part A.
ans = -1The "impossible" value, kept if no day ever works.
while low <= high:Until the two ends cross.
mid = low + (high - low) // 2The middle day (overflow-safe form).
ans = mid high = mid - 1Works: save it, then look for an earlier day.
low = mid + 1Doesn't work: the answer is a later day.
canMake(...)Exactly the same as in Part A.

8Dry run (hand tables)

Run 1: bloomDay = [1, 10, 3, 10, 2], m = 3, k = 1. low = 1, high = 10.

steplowhighmidopen on day midbouquetscanMake?decisionthrown away
111051, 3, 23yesans = 5, high = 4days 5 … 10
21421, 22nolow = 3days 1 … 2
33431, 3, 23yesans = 3, high = 2days 3 … 4
end32low > high → return 3 ✓
day12345678910
step 1123456789103 bouquets → go left
step 2123456789102 bouquets → go right
step 3123456789103 bouquets → ans = 3, go left (nothing left)

Run 2 (shows the adjacency reset): bloomDay = [7, 7, 7, 7, 12, 7, 7], m = 2, k = 3. Base case: 6 ≤ 7 ✓. low = 7, high = 12.

steplowhighmidwalk with countbouquetscanMake?decision
171291,2,3→B,0 · 1 · 12 closed → 0 · 1, 21nolow = 10
2101211same as above (12 still closed)1nolow = 12
31212121,2,3→B,0 · 1,2,3→B,0 · 12yesans = 12, high = 11
end1211return 12 ✓

The circled 12 is where the chain breaks: before it we held 1 flower, after it we start again from 0. That's exactly the else: count = 0 line.

9Complexity & remember

Remember m Bouquetsm × k > n → −1. Search days min … max. canMake: open → count, at k → bouquet + reset; closed → reset. Works → save, go left.

Part C · Revision page

Brute forceBinary search on answer
base casem × k > n → −1
rangemin(bloomDay) … max(bloomDay)
walkday by day, upwardtest mid, drop half
checkcount adjacent open flowers; at k → bouquet; closed → reset; bouquets ≥ m
time10⁹ × 10⁵ = 10¹⁴ → TLE30 × 10⁵ ✓
problemanswer is a…lowhighimpossible?
Koko (14)speed1max(piles)never
Ship packages (15)capacitymax(weights)sum(weights)never
Min speed (16)speed110⁷hour ≤ n − 1
m bouquets (18)daymin(bloomDay)max(bloomDay)m × k > n
If you remember only 5 lines 1. Not enough flowers (m × k > n) → −1 straight away.
2. Search the day between min and max of bloomDay.
3. canMake: open → count += 1; count == k → bouquet, count = 0; closed → count = 0.
4. Works → ans = mid, high = mid − 1. Fails → low = mid + 1.
5. Pattern = choose low/high + write check. Min → go left on yes; max → go right on yes.
Mistakes to avoid ✗ forgetting count = 0 when a flower is closed (non-adjacent flowers get joined)
✗ forgetting count = 0 after making a bouquet
✗ bloom < day instead of bloom <= day (a flower is ready on its bloom day)
✗ in Java/C++: m * k in int (up to 10¹¹, overflow)
✗ skipping the base case and searching anyway
test it yourself (paste under the Part B solution)
s = Solution()
print(s.minDays([1, 10, 3, 10, 2], 3, 1))          # 3
print(s.minDays([1, 10, 3, 10, 2], 3, 2))          # -1  (needs 6 flowers, has 5)
print(s.minDays([7, 7, 7, 7, 12, 7, 7], 2, 3))     # 12
print(s.minDays([1000000000, 1000000000], 1, 1))   # 1000000000
print(s.minDays([1, 10, 2, 9, 3, 8, 4, 7, 5, 6], 4, 2))   # 9

Based on this video: Minimum Number of Days to Make m Bouquets | Binary Search on Answer