Maximum Number of Balloons
EasyPrompt
Given a string text, you want to use the characters of text to form as many instances of the word "balloon" as possible.
You can use each character in text at most once. Return the maximum number of instances that can be formed.
Example 1:
Input: text = "nlaebolko"
Output: 1Example 2:
Input: text = "loonbalxballpoon"
Output: 2Example 3:
Input: text = "leetcode"
Output: 0
Constraints:
1 <= text.length <= 104textconsists of lower case English letters only.
Note: This question is the same as 2287: Rearrange Characters to Make Target String.
Approaches
3 approaches with complexity analysis and trade-offs.
This approach simulates the process of forming the word 'balloon' one by one. It repeatedly scans the input string to find and 'use up' the necessary characters ('b', 'a', 'l', 'l', 'o', 'o', 'n') for one instance of 'balloon'. The process continues until the required characters for a new 'balloon' cannot be found.
Algorithm
- Initialize
balloonsCountto 0. - Convert the input
textstring to a mutable list of characters, for example, anArrayList. - Start a loop that continues indefinitely (
while(true)). - Inside the loop, attempt to find and remove the characters required for one "balloon": 'b', 'a', 'l', 'l', 'o', 'o', 'n'.
- Use a boolean flag,
canForm, initialized totrueat the start of each iteration. - For each character in the word "balloon", check if it exists in the list. If it does, remove one occurrence. If it doesn't, set
canFormtofalseand stop checking for the current iteration. - After checking all characters for one "balloon", if
canFormis stilltrue, it means a balloon was successfully formed, so incrementballoonsCount. - If
canFormisfalse, it means we couldn't find all the necessary characters, so we break out of the main loop. - Finally, return
balloonsCount.
Walkthrough
We can model this by converting the input string into a more mutable data structure, like a list of characters. We then enter a loop. In each iteration, we attempt to find and remove one 'b', one 'a', two 'l's, two 'o's, and one 'n'. If we successfully remove all seven characters, we increment our count of formed 'balloons' and continue to the next iteration. If at any point we fail to find a required character, it means we cannot form another 'balloon', so we break the loop and return the current count. This method is intuitive but inefficient because it involves multiple passes over a shrinking data structure.
import java.util.ArrayList;import java.util.List; class Solution { public int maxNumberOfBalloons(String text) { List<Character> charList = new ArrayList<>(); for (char c : text.toCharArray()) { charList.add(c); } int balloonsCount = 0; String balloon = "balloon"; while (true) { boolean canForm = true; for (char ch : balloon.toCharArray()) { if (charList.contains(ch)) { // remove(Object) is important here to remove the character, not by index charList.remove(Character.valueOf(ch)); } else { canForm = false; break; } } if (canForm) { balloonsCount++; } else { break; } } return balloonsCount; }}Complexity
Time
O(N^2), where N is the length of the input string `text`. In the worst case, we can form `k = N/7` balloons. For each balloon, we iterate through the `balloon` string (7 characters) and for each character, we search and remove from a list of size up to N. Searching (`contains`) and removing (`remove(Object)`) from an `ArrayList` both take O(N) time. Thus, the complexity is roughly `k * 7 * N`, which simplifies to O(N^2).
Space
O(N), where N is the length of `text`. We need to store a copy of the input string in a mutable data structure like an `ArrayList`.
Trade-offs
Pros
Simple to understand and conceptualize.
Directly follows the logic described in the problem statement.
Cons
Extremely inefficient with a time complexity of O(N^2).
Becomes very slow for large input strings, likely leading to a 'Time Limit Exceeded' error on coding platforms.
Uses O(N) extra space to store a mutable copy of the string.
A much more efficient approach is to count the frequency of each character in the input string text first. After counting, we can directly calculate how many 'balloons' can be formed. The number of 'balloons' is limited by the character that is least available, considering that 'l' and 'o' are needed twice.
Algorithm
- Create a
HashMap<Character, Integer>to store the frequency of each character. - Iterate through each character
cof the input stringtext. - For each character, update its count in the HashMap. If the character is already a key, increment its value; otherwise, add it with a value of 1. This can be done efficiently using
map.put(c, map.getOrDefault(c, 0) + 1). - After populating the map, retrieve the counts for the characters required for "balloon": 'b', 'a', 'l', 'o', 'n'. Use
map.getOrDefault(char, 0)to safely get counts, which will be 0 if the character is not present intext. - Calculate the number of "balloons" that can be formed from 'l's and 'o's by dividing their counts by 2 (using integer division).
- The maximum number of "balloons" is limited by the least available character. Find the minimum of the following five values:
count('b'),count('a'),count('l')/2,count('o')/2, andcount('n'). - Return this minimum value.
Walkthrough
This method involves a single pass through the input string to build a frequency map (a HashMap) of all its characters. Once we have the counts of every character, we can determine the maximum number of 'balloons'. We need one 'b', one 'a', and one 'n', but two 'l's and two 'o's for each 'balloon'. Therefore, the number of 'balloons' is limited by count('b'), count('a'), count('n'), count('l') / 2, and count('o') / 2. The final answer is the minimum of these five values.
import java.util.HashMap;import java.util.Map; class Solution { public int maxNumberOfBalloons(String text) { Map<Character, Integer> counts = new HashMap<>(); for (char c : text.toCharArray()) { counts.put(c, counts.getOrDefault(c, 0) + 1); } int countB = counts.getOrDefault('b', 0); int countA = counts.getOrDefault('a', 0); int countL = counts.getOrDefault('l', 0); int countO = counts.getOrDefault('o', 0); int countN = counts.getOrDefault('n', 0); // For 'l' and 'o', we need two for each balloon. int result = Math.min(countB, countA); result = Math.min(result, countL / 2); result = Math.min(result, countO / 2); result = Math.min(result, countN); return result; }}Complexity
Time
O(N), where N is the length of `text`. We iterate through the string once to build the frequency map. The subsequent operations (map lookups and finding the minimum) take constant time.
Space
O(k), where k is the number of unique characters in `text`. Since the input is restricted to lowercase English letters, k is at most 26. Therefore, the space complexity is considered constant, O(1).
Trade-offs
Pros
Highly efficient with a linear time complexity.
Optimal time complexity as we must inspect every character at least once.
Uses constant extra space, as the number of unique characters is fixed (at most 26).
More general than the array approach; it would work for any character set (e.g., Unicode) without modification.
Cons
Uses a HashMap, which has some constant factor overhead due to hashing and potential collisions compared to a simple array.
Slightly more complex to write than the array-based approach for this specific problem.
This approach is an optimization of the frequency counting method. Since the input string consists only of lowercase English letters, we can use a fixed-size array of 26 integers instead of a HashMap to store character frequencies. This is generally faster in practice due to direct memory access and better cache locality.
Algorithm
- Create an integer array,
charCounts, of size 26, and initialize all its elements to 0. This array will store the frequency of each lowercase English letter. - Iterate through each character
cof the input stringtext. - For each character, increment the count at the corresponding index in the array. The index can be calculated as
c - 'a'. So, we performcharCounts[c - 'a']++. - After the loop finishes, the
charCountsarray contains the frequency of every character intext. - Retrieve the counts for the required characters by accessing the array at their respective indices:
countB = charCounts['b' - 'a'],countA = charCounts['a' - 'a'], and so on. - Calculate the number of "balloons" possible from 'l's and 'o's by dividing their counts by 2.
- The result is the minimum of the available counts:
min(countB, countA, countL/2, countO/2, countN). - Return this final minimum value.
Walkthrough
We initialize an integer array of size 26 to all zeros. Each index in the array corresponds to a letter of the alphabet (e.g., index 0 for 'a', index 1 for 'b', etc.). We make a single pass through the input string text. For each character, we increment the count at the corresponding index in our frequency array. After populating the array, we retrieve the counts for 'b', 'a', 'l', 'o', 'n' by accessing the appropriate indices. The logic to calculate the maximum number of 'balloons' remains the same: find the minimum of count('b'), count('a'), count('l') / 2, count('o') / 2, and count('n').
class Solution { public int maxNumberOfBalloons(String text) { int[] charCounts = new int[26]; for (char c : text.toCharArray()) { charCounts[c - 'a']++; } int countB = charCounts['b' - 'a']; int countA = charCounts['a' - 'a']; int countL = charCounts['l' - 'a']; int countO = charCounts['o' - 'a']; int countN = charCounts['n' - 'a']; // Find the minimum number of balloons we can form. // The number of 'l's and 'o's must be divided by 2. int min = countB; min = Math.min(min, countA); min = Math.min(min, countL / 2); min = Math.min(min, countO / 2); min = Math.min(min, countN); return min; }}Complexity
Time
O(N), where N is the length of `text`. We perform a single pass over the string to count frequencies. All other operations are constant time.
Space
O(1). We use an integer array of fixed size 26, which does not depend on the input size.
Trade-offs
Pros
Optimal time complexity of O(N).
Optimal space complexity of O(1).
Extremely fast in practice due to the use of an array, which avoids hashing overhead and benefits from cache-friendly contiguous memory access.
Cons
This specific optimization is only applicable because the character set is known and small (e.g., lowercase English letters). It is less flexible than a HashMap if the character set were larger or unknown.
Solutions
Solution
class Solution {public int maxNumberOfBalloons(String text) { int[] cnt = new int[26]; for (int i = 0; i < text.length(); ++i) { ++cnt[text.charAt(i) - 'a']; } cnt['l' - 'a'] >>= 1; cnt['o' - 'a'] >>= 1; int ans = 1 << 30; for (char c : "balon".toCharArray()) { ans = Math.min(ans, cnt[c - 'a']); } return ans; }}class Solution {public: int maxNumberOfBalloons(string text) { int cnt[26]{}; for (char c : text) { ++cnt[c - 'a']; } cnt['o' - 'a'] >>= 1; cnt['l' - 'a'] >>= 1; int ans = 1 << 30; string t = "balon"; for (char c : t) { ans = min(ans, cnt[c - 'a']); } return ans; }};class Solution: def maxNumberOfBalloons(self, text: str) -> int: cnt = Counter(text) cnt['o'] >>= 1 cnt['l'] >>= 1 return min(cnt[c] for c in 'balon')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.