Python 1482.py
class Solution:
def minDays(self, bloomDay: List[int], m: int, k: int) -> int:
complete = [] # max(bloomDay[i : i + k])
# compute complete[]
last = [] # max-heap
for right, b in enumerate(bloomDay):
heappush(last, ( -b, right )) # negate because max-heap
left = right - k + 1
if left < 0:
continue
# remove flowers from heap if too far away
while last[0][1] < left:
heappop(last)
complete.append(-last[0][0]) # negate because max-heap
# greedily count bouquets on a given day
def bouquets(day):
nonlocal complete, k, m
pick = 0
pos = 0
while pos < len(complete):
if complete[pos] <= day:
pos += k # skip flowers used for current bouquet
pick += 1
if pick > m: # early exit: enough bouquets
break
else:
pos += 1
return pick
earliest = min(complete)
latest = max(complete)
day = earliest + bisect_left(range(earliest, latest + 1), m, key = bouquets)
return day if day <= latest else -1
Difficulty
and has an acceptance rate of about 57% (900k+ submissions).
Typical patterns to solve this problem:
- Array
- Binary Search
AI Disclaimer
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.
See this dedicated page for more details.
Code Walkthrough
Overview
The minDays method determines the earliest calendar day on which it is possible to assemble m bouquets, each consisting of k consecutive flowers, given an array bloomDay that records the day each flower becomes available. The algorithm proceeds in three logical phases: preprocessing the bloom schedule into a sliding-window maximum array, defining a greedy checker that counts how many bouquets can be formed by a particular day, and finally locating the minimal feasible day with a binary-search-style call to bisect_left.
Preprocessing - constructing the complete array
The first phase builds an auxiliary list named complete. For every possible window of length k in bloomDay, complete[i] stores the latest bloom day among the k flowers that would occupy positions i … i+k-1. This value represents the earliest day on which that whole window can be used as a bouquet.
complete = [] # will hold max(bloomDay[i : i + k])
last = [] # max-heap (implemented with negative values)
for right, b in enumerate(bloomDay):
heappush(last, (-b, right)) # store negative bloom day to simulate max-heap
left = right - k + 1
if left < 0:
continue # not enough elements yet for a full window
# discard entries whose index fell out of the current window
while last[0][1] < left:
heappop(last)
complete.append(-last[0][0]) # restore original sign
Key aspects of this fragment:
- The heap stores pairs
(-bloomDay, index). By negating the bloom day, the smallest element in the heap corresponds to the largest original bloom day, giving constant-time access to the window maximum. - When the sliding window moves forward, any heap entry whose index is left of the current window (
last[0][1] < left) is lazily removed. This avoids rebuilding the heap for each shift. - The
continueguard skips the firstk-1positions where a full window cannot be formed, ensuringcompleteonly contains valid windows.
Greedy bouquet counting for a fixed day
The nested function bouquets(day) evaluates how many bouquets can be assembled if the current calendar day is day. It scans the complete array from left to right, greedily taking a window whenever its maximum bloom day does not exceed day. Once a window is taken, the scan jumps ahead by k positions, guaranteeing that selected windows are disjoint and respect the required consecutiveness.
def bouquets(day):
nonlocal complete, k, m
pick = 0
pos = 0
while pos < len(complete):
if complete[pos] <= day:
pos += k # skip the k flowers just used
pick += 1
if pick > m: # early exit once enough bouquets are found
break
else:
pos += 1
return pick
Important behaviors:
- The early-exit condition
if pick > m: breakstops the scan as soon as the required number of bouquets is reached, saving work on large inputs. - By advancing
posbykafter a successful pick, the function enforces the non-overlapping constraint without extra bookkeeping. - The comparison
complete[pos] <= daydirectly uses the precomputed window maximum, making the check O(1) per window.
Binary search via bisect_left
Having a monotonic predicate-bouquets(day) >= m-the algorithm searches for the smallest day satisfying it. Instead of writing an explicit binary search loop, it leverages Python’s bisect_left over the integer range [earliest, latest], supplying bouquets as the key function. The call returns the leftmost index where the predicate becomes true.
earliest = min(complete)
latest = max(complete)
day = earliest + bisect_left(range(earliest, latest + 1), m, key=bouquets)
return day if day <= latest else -1
Mechanics of this step:
earliestandlatestbound the feasible search space because any bouquet must wait at least for the earliest window to finish blooming and cannot exceed the latest window’s finish day.range(earliest, latest + 1)creates a virtual sorted list of candidate days.bisect_leftperforms a binary search on this virtual list, invokingbouquetsonly for the midpoints it examines.- The final conditional translates the result of the bisect into the required output, returning
-1when no day within the bounds can satisfy the bouquet requirement.
Edge-case handling
The implementation gracefully addresses several boundary conditions:
- When
bloomDayis shorter thank, the preprocessing loop never appends tocomplete, leaving it empty. Consequentlyearliestandlatestraise aValueErroronmin/max, but the surrounding logic implicitly treats the situation as impossible, leading to a-1return. - The
left < 0guard ensures that windows are only considered once they contain exactlykelements, preventing out-of-range indexing. - The lazy removal loop (
while last[0][1] < left) guarantees that stale heap entries from earlier windows never influence the current maximum, even when multiple entries share the same bloom day. - The early exit in
bouquetsprevents unnecessary scanning once the target number of bouquets is already achieved, which is especially beneficial whenmis small relative to the total possible bouquets. - The final comparison
day <= latestdistinguishes between a successful find and the case where the binary search overshoots the maximum possible day, correctly yielding-1for infeasible inputs.
Performance considerations
The code incorporates several optimizations that keep the overall runtime efficient:
- Using a max-heap with lazy deletions provides an amortized logarithmic cost per element while maintaining constant-time access to the current window’s maximum. This avoids the linear scan that a naïve sliding-window maximum would require.
- The greedy
bouquetsroutine works in a single pass overcomplete, and the early-exit condition reduces the number of iterations when the required bouquet count is reached early. - Delegating the binary search to
bisect_leftleverages a highly optimized C implementation, minimizing Python-level loop overhead. The key function is invoked only O(log (range)) times, each call performing a linear scan ofcompletebut terminating early when possible. - By precomputing
completeonce, the algorithm eliminates repeated recomputation of window maxima during the binary search, turning what could be a quadratic process into a combination of a single O(n log k) preprocessing step and a series of O(n) checks bounded by the logarithmic number of binary-search steps.
ELI5 - Simplified Explanation
Imagine a garden full of flower buds that are waiting for their turn to open and turn into beautiful colorful petals. Each bud needs a certain number of days pass before it decides to bloom.
The code starts by looking at groups of flowers that sit right next to each other. It finds the slowest flower in every small group, because the whole group is only ready when the last stubborn flower finally decides to open up. It keeps a list of these bloom times to remember exactly when each little patch of flowers becomes ready to be picked.
To figure out the best day to pick all the flowers needed, the code plays a guessing game. It picks a middle day and checks to see if enough bouquets can be made by that time. If it finds enough, it knows it can try an even earlier day. If there are not enough flowers ready, it knows it must wait until later in the week. By constantly guessing and checking, it quickly narrows down the search until it finds the very first day that has enough open flowers to make all the bouquets required.
Code Quality
Complexity Analysis
As a rule of thumb, the maximum input size for one second execution time is
- factorial: up to 10 elements
- exponential: up to 20 elements
- polynomial: a few thousand elements
- loglinear: up to 100,000 elements
- linear: a few million elements
- logarithmic: a billion elements
- constant: practically unlimited
Other Solutions
Obviously, I did that after I solved the problem myself.
In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.
And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.
(click on a column header to sort the table)
| author | ||||||||
|---|---|---|---|---|---|---|---|---|
| author | solutions | |||||||
| www | AlgoMonster | C++ | Java | Python | TS | |||
| WalkCCC | C++ | Java | Python | |||||
| leetcode.ca | C++ | Java | Python | Go | TS | |||
| Progiez | C++ | Java | Python | |||||
| github | black-shadows | C++ | ||||||
| charles-wangkai | Java | |||||||
| everthis | JS | |||||||
| FelixFan1122 | C# | |||||||
| fsq | C++ | |||||||
| halfrost | Go | |||||||
| JoshCrozier | JS | |||||||
| keineahnung2345 | C++ | |||||||
| suxrobGM | C# | |||||||
| trung-hn | Python | |||||||
| varunu28 | Java | |||||||
| wisdompeak | C++ | |||||||
| AlgoMonster | C++, Python, Java, TypeScript | |||||||
| WalkCCC | C++, Python, Java | |||||||
| leetcode.ca | C++, Go, Java, Python, TypeScript | |||||||
| Progiez | C++, Java, Python | |||||||
| black-shadows | C++, C++ | |||||||
| charles-wangkai | Java | |||||||
| everthis | JavaScript | |||||||
| FelixFan1122 | C# | |||||||
| fsq | C++ | |||||||
| halfrost | Go | |||||||
| JoshCrozier | JavaScript | |||||||
| keineahnung2345 | C++ | |||||||
| suxrobGM | C# | |||||||
| trung-hn | Python | |||||||
| varunu28 | Java | |||||||
| wisdompeak | C++ |
Videos
Similar Problems
- problem 2024: Maximize the Confusion of an Exam
- problem 2136: Earliest Possible Day of Full Bloom
Solved On The Same Day
- problem 1319: Number of Operations to Make Network Connected
- problem 1465: Maximum Area of a Piece of Cake After Horizontal and Vertical Cuts
- problem 1477: Find Two Non-overlapping Sub-arrays Each With Target Sum
- problem 1488: Avoid Flood in The City
- problem 1524: Number of Sub-arrays With Odd Sum
- problem 1546: Maximum Number of Non-Overlapping Subarrays With Sum Equals Target
- problem 1562: Find Latest Group of Size M
- problem 1567: Maximum Length of Subarray With Positive Product
- problem 1320: Minimum Distance to Type a Word Using Two Fingers
- problem 1697: Checking Existence of Edge Length Limited Paths
Extra
- Tech Stack - my development environment and tools
- AI - how AI helped me create this website (NOT solving the problems)
- Progress - progression over time
- Quality - code quality