It is a sweltering summer day, and a boy wants to buy some ice cream bars.
At the store, there are n
ice cream bars. You are given an array costs
of length n
, where costs[i]
is the price of the ith
ice cream bar in coins. The boy initially has coins
coins to spend, and he wants to buy as many ice cream bars as possible.
Note: The boy can buy the ice cream bars in any order.
Return the maximum number of ice cream bars the boy can buy with coins
coins.
You must solve the problem by counting sort.
Example 1:
Input: costs = [1,3,2,4,1], coins = 7 Output: 4 Explanation: The boy can buy ice cream bars at indices 0,1,2,4 for a total price of 1 + 3 + 2 + 1 = 7.
Example 2:
Input: costs = [10,6,8,7,7,8], coins = 5 Output: 0 Explanation: The boy cannot afford any of the ice cream bars.
Example 3:
Input: costs = [1,6,3,1,2,5], coins = 20 Output: 6 Explanation: The boy can buy all the ice cream bars for a total price of 1 + 6 + 3 + 1 + 2 + 5 = 18.
Constraints:
costs.length == n
1 <= n <= 105
1 <= costs[i] <= 105
1 <= coins <= 108
This problem asks to find the maximum number of ice cream bars a boy can buy with a given amount of coins, given an array of ice cream bar costs. The key insight is that to maximize the number of bars, we should buy the cheapest ones first. This leads to a greedy approach.
Sort the costs: We sort the costs
array in ascending order. This ensures we consider the cheapest ice cream bars first.
Iterate and buy: We iterate through the sorted costs
array. For each ice cream bar:
coins >= costs[i]
).coins
(coins -= costs[i]
).i
).All bars affordable: If the loop completes without running out of coins, it means we could afford all the ice cream bars, so we return the total number of ice cream bars (len(costs)
or costs.length
).
Time Complexity: The dominant operation is sorting the costs
array. Most sorting algorithms (like merge sort or quicksort used in Python's sort()
and Java's Arrays.sort()
) have a time complexity of O(n log n), where n is the number of ice cream bars. The subsequent iteration through the sorted array takes O(n) time. Therefore, the overall time complexity is O(n log n), dominated by the sorting step.
Space Complexity: The space complexity depends on the sorting algorithm used. In-place sorting algorithms like quicksort have O(log n) space complexity in the average case due to the recursive call stack. Merge sort generally uses O(n) space. Python's list.sort()
uses Timsort (a hybrid sorting algorithm), which is generally O(n) in the worst case but can be closer to O(log n) in practice. Java's Arrays.sort()
uses a hybrid merge sort/insertion sort approach, also roughly O(n) in the worst case and closer to O(log n) on average. Thus, the space complexity is typically considered O(n) in the worst case, or potentially O(log n) on average, depending on the specific sorting implementation. If we consider only the extra space used besides the input array, we can consider it to be O(1) (for the counter in the iterative approach).
The code examples below demonstrate the greedy approach in several programming languages. They all follow the same basic algorithm: sort, iterate, and buy.
def maxIceCream(costs: list[int], coins: int) -> int:
costs.sort() # Sort in ascending order
bars_bought = 0
for cost in costs:
if coins >= cost:
coins -= cost
bars_bought += 1
else:
break # Cannot afford anymore
return bars_bought
import java.util.Arrays;
class Solution {
public int maxIceCream(int[] costs, int coins) {
Arrays.sort(costs); // Sort in ascending order
int barsBought = 0;
for (int cost : costs) {
if (coins >= cost) {
coins -= cost;
barsBought++;
} else {
break; // Cannot afford anymore
}
}
return barsBought;
}
}
#include <algorithm>
#include <vector>
class Solution {
public:
int maxIceCream(std::vector<int>& costs, int coins) {
std::sort(costs.begin(), costs.end()); // Sort in ascending order
int barsBought = 0;
for (int cost : costs) {
if (coins >= cost) {
coins -= cost;
barsBought++;
} else {
break; // Cannot afford anymore
}
}
return barsBought;
}
};
/**
* @param {number[]} costs
* @param {number} coins
* @return {number}
*/
var maxIceCream = function(costs, coins) {
costs.sort((a, b) => a - b); // Sort in ascending order
let barsBought = 0;
for (let cost of costs) {
if (coins >= cost) {
coins -= cost;
barsBought++;
} else {
break; // Cannot afford anymore
}
}
return barsBought;
};
These code examples all achieve the same result efficiently using a greedy strategy and sorting. The choice of language depends on your preference and the context of the problem's usage.