Number of Flowers in Full Bloom
HardPrompt
You are given a 0-indexed 2D integer array flowers, where flowers[i] = [starti, endi] means the ith flower will be in full bloom from starti to endi (inclusive). You are also given a 0-indexed integer array people of size n, where people[i] is the time that the ith person will arrive to see the flowers.
Return an integer array answer of size n, where answer[i] is the number of flowers that are in full bloom when the ith person arrives.
Example 1:
Input: flowers = [[1,6],[3,7],[9,12],[4,13]], people = [2,3,7,11]
Output: [1,2,2,2]
Explanation: The figure above shows the times when the flowers are in full bloom and when the people arrive.
For each person, we return the number of flowers in full bloom during their arrival.Example 2:
Input: flowers = [[1,10],[3,3]], people = [3,3,2]
Output: [2,2,1]
Explanation: The figure above shows the times when the flowers are in full bloom and when the people arrive.
For each person, we return the number of flowers in full bloom during their arrival.
Constraints:
1 <= flowers.length <= 5 * 104flowers[i].length == 21 <= starti <= endi <= 1091 <= people.length <= 5 * 1041 <= people[i] <= 109
Approaches
3 approaches with complexity analysis and trade-offs.
This approach directly simulates the process described in the problem. For each person's arrival time, we iterate through every flower's blooming interval to check if the flower is in bloom at that specific time.
Algorithm
-
- Initialize an integer array
ansof sizepeople.length.
- Initialize an integer array
-
- For each person
ifrom0topeople.length - 1:
- For each person
-
- Initialize
count = 0.
- Initialize
-
- Let
arrivalTime = people[i].
- Let
-
- For each
flowerinflowers:
- For each
-
-
If `flower[0] <= arrivalTime <= flower[1]`, increment `count`.
-
-
- Set
ans[i] = count.
- Set
-
- Return
ans.
- Return
Walkthrough
We initialize an answer array, ans, with the same length as the people array.
We then loop through each person i. For each person, we get their arrival time t = people[i].
Inside this loop, we start another loop to go through every flower interval [start, end] in the flowers array.
For each flower, we check if the person's arrival time t is within the inclusive interval [start, end]. The condition is start <= t && t <= end.
We maintain a counter for the current person. If the condition is true, we increment the counter.
After checking all flowers for the current person, the final count is stored in ans[i].
This process is repeated for all people.
The final ans array is returned.
class Solution { public int[] fullBloomFlowers(int[][] flowers, int[] people) { int n = people.length; int[] ans = new int[n]; for (int i = 0; i < n; i++) { int time = people[i]; int count = 0; for (int[] flower : flowers) { if (flower[0] <= time && time <= flower[1]) { count++; } } ans[i] = count; } return ans; }}Complexity
Time
O(N * M), where N is the number of people and M is the number of flowers. For each of the N people, we iterate through all M flowers.
Space
O(N) for the output array. If the output array is not considered, the space complexity is O(1).
Trade-offs
Pros
Simple to understand and implement.
Cons
Very inefficient and will likely result in a Time Limit Exceeded (TLE) error for large inputs due to its quadratic time complexity.
This approach improves upon the brute-force method by pre-processing the flower data. Instead of checking intervals for each person, we can rephrase the problem: for a given time t, how many flowers have started blooming (start <= t) minus how many have finished blooming (end < t)? This can be answered efficiently using binary search on sorted lists of start and end times.
Algorithm
-
- Create two arrays,
startsandends, of sizeflowers.length.
- Create two arrays,
-
- Populate
startswithflower[0]andendswithflower[1]for all flowers.
- Populate
-
- Sort the
startsandendsarrays.
- Sort the
-
- Initialize an answer array
ansof sizepeople.length.
- Initialize an answer array
-
- For each person's arrival time
tinpeople:
- For each person's arrival time
-
- Find
startedCount, the number of flowers withstart_time <= t, using binary search onstarts. This is the index of the first element greater thant.
- Find
-
- Find
endedCount, the number of flowers withend_time < t, using binary search onends. This is the index of the first element greater than or equal tot.
- Find
-
- The number of blooming flowers is
startedCount - endedCount. Store this inans.
- The number of blooming flowers is
-
- Return
ans.
- Return
Walkthrough
First, we create two separate arrays, starts and ends, to store the start and end times of all flowers, respectively.
We populate these arrays by iterating through the flowers array.
Then, we sort both the starts and ends arrays in ascending order. This is the key pre-processing step.
For each person's arrival time t in the people array, we perform two binary searches:
- Count of flowers started: We use binary search on the
startsarray to find the number of flowers that have started blooming by timet. This is equivalent to finding the count ofstart_i <= t. A standard binary search can find the insertion point fort+1(or find the upper bound fort), which gives us this count. - Count of flowers ended: We use binary search on the
endsarray to find the number of flowers that have finished blooming before timet. This is equivalent to finding the count ofend_i < t. A standard binary search can find the insertion point fort(or find the lower bound fort), which gives us this count. The number of flowers in full bloom at timetis the difference:(flowers started) - (flowers ended). We store this result for each person and return the final answer array.
import java.util.Arrays; class Solution { public int[] fullBloomFlowers(int[][] flowers, int[] people) { int m = flowers.length; int[] starts = new int[m]; int[] ends = new int[m]; for (int i = 0; i < m; i++) { starts[i] = flowers[i][0]; ends[i] = flowers[i][1]; } Arrays.sort(starts); Arrays.sort(ends); int n = people.length; int[] ans = new int[n]; for (int i = 0; i < n; i++) { int time = people[i]; int started = binarySearchUpperBound(starts, time); int ended = binarySearchLowerBound(ends, time); ans[i] = started - ended; } return ans; } // Finds number of elements <= target private int binarySearchUpperBound(int[] arr, int target) { int left = 0, right = arr.length; while (left < right) { int mid = left + (right - left) / 2; if (arr[mid] > target) { right = mid; } else { left = mid + 1; } } return left; } // Finds number of elements < target private int binarySearchLowerBound(int[] arr, int target) { int left = 0, right = arr.length; while (left < right) { int mid = left + (right - left) / 2; if (arr[mid] >= target) { right = mid; } else { left = mid + 1; } } return left; }}Complexity
Time
O(M log M + N log M), where N is the number of people and M is the number of flowers. Sorting takes O(M log M). Then for each of the N people, we perform two binary searches on arrays of size M, which takes O(log M) each.
Space
O(M + N). We need O(M) space for the `starts` and `ends` arrays and O(N) for the result array.
Trade-offs
Pros
Significantly more efficient than the brute-force approach for large inputs.
Cons
Can be further optimized by avoiding repeated binary searches if the people's arrival times are also sorted.
This is the most efficient approach, often referred to as a sweep-line algorithm. It processes events (flower start, flower end, person arrival) in chronological order. By sorting both the flower times and people's arrival times, we can iterate through them in a coordinated fashion using pointers, calculating the number of blooming flowers incrementally.
Algorithm
-
- Create and sort
startsandendsarrays fromflowers.
- Create and sort
-
- Create a new data structure (e.g., 2D array) to store
[people[i], i]pairs.
- Create a new data structure (e.g., 2D array) to store
-
- Sort these pairs based on the arrival time
people[i].
- Sort these pairs based on the arrival time
-
- Initialize
s_ptr = 0,e_ptr = 0, andcurrent_blooming = 0.
- Initialize
-
- Initialize an answer array
ansof sizepeople.length.
- Initialize an answer array
-
- Iterate through the sorted people pairs
[time, original_index]:
- Iterate through the sorted people pairs
-
- While
s_ptris within bounds andstarts[s_ptr] <= time, incrementcurrent_bloomingands_ptr.
- While
-
- While
e_ptris within bounds andends[e_ptr] < time, decrementcurrent_bloomingande_ptr.
- While
-
- Set
ans[original_index] = current_blooming.
- Set
-
- Return
ans.
- Return
Walkthrough
The core idea is to count the net change in blooming flowers as time progresses. A flower starting to bloom is a +1 event, and a flower ending its bloom is a -1 event.
First, create and sort starts and ends arrays from the flowers data, just like in the previous approach.
To handle the people's arrival times in order while preserving their original positions for the output, we create a 2D array or a list of pairs, sortedPeople, where each element is [arrivalTime, originalIndex]. We then sort this sortedPeople array based on arrivalTime.
We initialize pointers for the starts array (s_ptr), the ends array (e_ptr), and a variable current_blooming to 0.
We iterate through the sortedPeople array. For each person [time, orig_idx]:
- We advance
s_ptrthrough thestartsarray, incrementingcurrent_bloomingfor every flower that starts blooming on or before the current person's arrival time (starts[s_ptr] <= time). - We advance
e_ptrthrough theendsarray, decrementingcurrent_bloomingfor every flower that has finished blooming before the person's arrival (ends[e_ptr] < time). - After these updates,
current_bloomingholds the exact number of flowers in bloom attime. We store this value in our answer array at the person's original index:ans[orig_idx] = current_blooming. After iterating through all people, theansarray is complete and can be returned.
import java.util.Arrays;import java.util.Comparator; class Solution { public int[] fullBloomFlowers(int[][] flowers, int[] people) { int m = flowers.length; int[] starts = new int[m]; int[] ends = new int[m]; for (int i = 0; i < m; i++) { starts[i] = flowers[i][0]; ends[i] = flowers[i][1]; } Arrays.sort(starts); Arrays.sort(ends); int n = people.length; int[][] sortedPeople = new int[n][2]; for (int i = 0; i < n; i++) { sortedPeople[i][0] = people[i]; sortedPeople[i][1] = i; } Arrays.sort(sortedPeople, Comparator.comparingInt(a -> a[0])); int[] ans = new int[n]; int s_ptr = 0; int e_ptr = 0; int current_blooming = 0; for (int i = 0; i < n; i++) { int time = sortedPeople[i][0]; int originalIndex = sortedPeople[i][1]; // Count flowers that have started by this time while (s_ptr < m && starts[s_ptr] <= time) { current_blooming++; s_ptr++; } // Count flowers that have ended before this time while (e_ptr < m && ends[e_ptr] < time) { current_blooming--; e_ptr++; } ans[originalIndex] = current_blooming; } return ans; }}Complexity
Time
O(M log M + N log N). Sorting `starts` and `ends` takes O(M log M). Sorting `people` with their indices takes O(N log N). The final coordinated traversal takes O(M + N) because each pointer only moves forward. The dominant part is the sorting.
Space
O(M + N). We need O(M) for `starts` and `ends`, and O(N) for storing sorted people with indices and for the result array.
Trade-offs
Pros
Most efficient solution with optimal time complexity. It avoids redundant computations by processing events in a single pass after sorting.
Cons
Slightly more complex to implement due to the need to track original indices and manage multiple pointers.
Solutions
Solution
class Solution {public int[] fullBloomFlowers(int[][] flowers, int[] people) { int n = flowers.length; int[] start = new int[n]; int[] end = new int[n]; for (int i = 0; i < n; ++i) { start[i] = flowers[i][0]; end[i] = flowers[i][1]; } Arrays.sort(start); Arrays.sort(end); int m = people.length; int[] ans = new int[m]; for (int i = 0; i < m; ++i) { ans[i] = search(start, people[i] + 1) - search(end, people[i]); } return ans; }private int search(int[] nums, int x) { int l = 0, r = nums.length; while (l < r) { int mid = (l + r) >> 1; if (nums[mid] >= x) { r = mid; } else { l = mid + 1; } } return l; }}class Solution {public: vector<int> fullBloomFlowers(vector<vector<int>> &flowers, vector<int> &people) { int n = flowers.size(); vector<int> start; vector<int> end; for (auto &f : flowers) { start.push_back(f[0]); end.push_back(f[1]); } sort(start.begin(), start.end()); sort(end.begin(), end.end()); vector<int> ans; for (auto &p : people) { auto r = upper_bound(start.begin(), start.end(), p) - start.begin(); auto l = lower_bound(end.begin(), end.end(), p) - end.begin(); ans.push_back(r - l); } return ans; }};class Solution: def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: start, end = sorted(a for a, _ in flowers), sorted(b for _, b in flowers) return [bisect_right(start, p) - bisect_left(end, p) for p in people]Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.