From a39596bdd94d710d7dfa86987e3886c9f9e0c389 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 21 Jun 2026 05:25:37 +0000 Subject: [PATCH] feat: add solution for 1833. Maximum Ice Cream Bars --- .../1833-maximum-ice-cream-bars/analysis.md | 60 +++++++++++++++++ .../1833-maximum-ice-cream-bars/problem.md | 65 +++++++++++++++++++ .../1833-maximum-ice-cream-bars/solution.go | 51 +++++++++++++++ .../solution_test.go | 30 +++++++++ 4 files changed, 206 insertions(+) create mode 100644 problems/1833-maximum-ice-cream-bars/analysis.md create mode 100644 problems/1833-maximum-ice-cream-bars/problem.md create mode 100644 problems/1833-maximum-ice-cream-bars/solution.go create mode 100644 problems/1833-maximum-ice-cream-bars/solution_test.go diff --git a/problems/1833-maximum-ice-cream-bars/analysis.md b/problems/1833-maximum-ice-cream-bars/analysis.md new file mode 100644 index 0000000..d314b4b --- /dev/null +++ b/problems/1833-maximum-ice-cream-bars/analysis.md @@ -0,0 +1,60 @@ +# 1833. Maximum Ice Cream Bars + +[LeetCode Link](https://leetcode.com/problems/maximum-ice-cream-bars/) + +Difficulty: Medium +Topics: Array, Greedy, Sorting, Counting Sort +Acceptance Rate: 75.4% + +## Hints + +### Hint 1 + +You want to maximize the *count* of items you buy, not which specific ones. When the goal is "as many as possible" and items have no other constraints tying them together, ask yourself: does the order in which I pick them matter, and is there an obviously "best first" choice? + +### Hint 2 + +This is a greedy problem. To fit the most bars into a fixed budget, always reach for the cheapest bar still available. If you sort the costs ascending and spend from the front, you can never do better by skipping a cheap bar in favor of a more expensive one. The only question left is *how* to sort efficiently. + +### Hint 3 + +Notice the constraint: `1 <= costs[i] <= 10^5`. The values live in a small, bounded range, which is the classic signal for **counting sort**. Instead of comparison-sorting in O(n log n), tally how many bars exist at each price into a frequency array, then walk the prices from cheapest to most expensive, buying as many as your coins allow at each price level. This gives a linear-time greedy. + +## Approach + +The core idea is greedy: to buy the maximum number of bars, always buy the cheapest ones first. Spending a coin on an expensive bar when a cheaper one is available can only reduce the total count, so sorting ascending and buying from the cheapest end is optimal. + +Because the problem explicitly asks for **counting sort**, we avoid a comparison sort and instead exploit the bounded value range (`costs[i] <= 10^5`): + +1. **Build a frequency table.** Create a `count` array indexed by price. For each cost `c`, increment `count[c]`. This buckets every bar by its price in O(n). + +2. **Walk prices from cheapest to most expensive.** For each price `p` from 1 up to the maximum cost: + - If `count[p]` is 0, skip it. + - Otherwise, figure out how many bars at this price we can afford: `affordable = coins / p`, capped at the number actually available `count[p]`. + - Add that many bars to the answer and subtract their total cost (`bought * p`) from `coins`. + - If after this we cannot afford even one more bar at the *current* price, then we certainly cannot afford anything more expensive either — so we can stop early. + +3. **Return the running count** of bars bought. + +**Walkthrough on Example 1:** `costs = [1,3,2,4,1]`, `coins = 7`. +- Frequency: price 1 → 2 bars, price 2 → 1, price 3 → 1, price 4 → 1. +- Price 1: can afford `7/1 = 7`, but only 2 exist → buy 2, coins = 5, total = 2. +- Price 2: can afford `5/2 = 2`, only 1 exists → buy 1, coins = 3, total = 3. +- Price 3: can afford `3/3 = 1`, 1 exists → buy 1, coins = 0, total = 4. +- Price 4: can afford `0/4 = 0` → stop. Answer: **4**. + +This is a satisfying problem — the greedy insight is intuitive once you see it, and the counting-sort twist is a clean exercise in recognizing when bounded inputs let you beat O(n log n). + +## Complexity Analysis + +Time Complexity: O(n + M), where `n` is the number of bars and `M` is the maximum cost value (here at most 10^5). Building the frequency table is O(n), and scanning the price buckets is O(M). + +Space Complexity: O(M) for the frequency array sized to the maximum cost. + +## Edge Cases + +- **Cannot afford any bar** (e.g., Example 2, all costs exceed `coins`): the loop never buys anything and returns 0. Make sure the affordability check correctly yields 0 here. +- **Can afford every bar** (Example 3): the budget is large enough that `count[p]` is always the binding limit, so every bar is bought. +- **Single bar** (`n == 1`): either you can afford it (return 1) or you cannot (return 0). +- **Duplicate prices**: many bars share the same price; the frequency table naturally handles this by bucketing, and you must cap purchases at the available count, not just affordability. +- **Empty input** (`len(costs) == 0`): defensively returns 0, since there is nothing to buy. (LeetCode guarantees `n >= 1`, but the code handles it cleanly.) diff --git a/problems/1833-maximum-ice-cream-bars/problem.md b/problems/1833-maximum-ice-cream-bars/problem.md new file mode 100644 index 0000000..50d259e --- /dev/null +++ b/problems/1833-maximum-ice-cream-bars/problem.md @@ -0,0 +1,65 @@ +--- +number: "1833" +frontend_id: "1833" +title: "Maximum Ice Cream Bars" +slug: "maximum-ice-cream-bars" +difficulty: "Medium" +topics: + - "Array" + - "Greedy" + - "Sorting" + - "Counting Sort" +acceptance_rate: 7537.5 +is_premium: false +created_at: "2026-06-21T05:24:15.805634+00:00" +fetched_at: "2026-06-21T05:24:15.805634+00:00" +link: "https://leetcode.com/problems/maximum-ice-cream-bars/" +date: "2026-06-21" +--- + +# 1833. Maximum Ice Cream Bars + +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` diff --git a/problems/1833-maximum-ice-cream-bars/solution.go b/problems/1833-maximum-ice-cream-bars/solution.go new file mode 100644 index 0000000..e02aa8e --- /dev/null +++ b/problems/1833-maximum-ice-cream-bars/solution.go @@ -0,0 +1,51 @@ +package main + +// Maximum Ice Cream Bars (LeetCode 1833) +// +// Approach: greedy + counting sort. Buying the cheapest bars first maximizes +// the number purchased. Since costs are bounded (1 <= costs[i] <= 10^5), we use +// counting sort: bucket bars by price into a frequency array, then walk prices +// from cheapest to most expensive, buying as many as the budget allows at each +// level. Runs in O(n + maxCost) time. +func maxIceCream(costs []int, coins int) int { + if len(costs) == 0 { + return 0 + } + + // Find the maximum cost to size the frequency table. + maxCost := 0 + for _, c := range costs { + if c > maxCost { + maxCost = c + } + } + + // count[p] is the number of bars priced at p. + count := make([]int, maxCost+1) + for _, c := range costs { + count[c]++ + } + + bought := 0 + for price := 1; price <= maxCost; price++ { + if count[price] == 0 { + continue + } + + // How many bars at this price can we afford? + affordable := coins / price + if affordable == 0 { + // Cannot afford even one at this price; all higher prices are + // also unaffordable, so we can stop early. + break + } + if affordable > count[price] { + affordable = count[price] + } + + bought += affordable + coins -= affordable * price + } + + return bought +} diff --git a/problems/1833-maximum-ice-cream-bars/solution_test.go b/problems/1833-maximum-ice-cream-bars/solution_test.go new file mode 100644 index 0000000..3f5c04b --- /dev/null +++ b/problems/1833-maximum-ice-cream-bars/solution_test.go @@ -0,0 +1,30 @@ +package main + +import "testing" + +func TestMaxIceCream(t *testing.T) { + tests := []struct { + name string + costs []int + coins int + expected int + }{ + {"example 1: buy four cheapest bars", []int{1, 3, 2, 4, 1}, 7, 4}, + {"example 2: cannot afford any bar", []int{10, 6, 8, 7, 7, 8}, 5, 0}, + {"example 3: afford all bars", []int{1, 6, 3, 1, 2, 5}, 20, 6}, + {"edge case: empty input", []int{}, 100, 0}, + {"edge case: single bar affordable", []int{5}, 5, 1}, + {"edge case: single bar unaffordable", []int{5}, 4, 0}, + {"edge case: all same price, partial buy", []int{2, 2, 2, 2}, 5, 2}, + {"edge case: exact budget for all", []int{3, 3, 3}, 9, 3}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := maxIceCream(tt.costs, tt.coins) + if result != tt.expected { + t.Errorf("maxIceCream(%v, %d) = %d, want %d", tt.costs, tt.coins, result, tt.expected) + } + }) + } +}