Minimum Shopping Cost with Vouchers
Alex is an influencer who loves shopping online and sharing his latest hauls with his followers. He's planning a big unboxing video featuring $n$ products from an e-commerce site. Each product has an original price prices[i], and Alex has vouchersCount discount vouchers to spend across his purchases.
Each voucher halves the current price of one item (using integer division), and you are allowed to use multiple vouchers for a single product. For example, if $k$ vouchers are applied to a product priced at $p$, its final cost becomes $\lfloor p / 2^k \rfloor$.
Return the minimum total cost for purchasing all items after optimally applying all (or some) vouchers.
Example 1
Input
prices = [10, 20, 30], vouchersCount = 2Output
35Explanation
To minimize the total cost, we should always apply a voucher to the current most expensive item. 1. Initial prices: [10, 20, 30]. The most expensive is 30. Applying 1 voucher: 30 / 2 = 15. Prices: [10, 20, 15]. 2. Current prices: [10, 20, 15]. The most expensive is 20. Applying 1 voucher: 20 / 2 = 10. Prices: [10, 10, 15]. Total cost: 10 + 10 + 15 = 35.
Example 2
Input
prices = [100, 200], vouchersCount = 5Output
50Explanation
Applying vouchers greedily to the highest price: 200->100, 100->50, 100->50, 50->25, 50->25. Final prices: [25, 25].
Example 3
Input
prices = [15, 25, 35], vouchersCount = 0Output
75
Constraints
1 <= prices.length <= 10⁵0 <= vouchersCount <= 10⁹1 <= prices[i] <= 10⁹- Each voucher application uses integer division (floor).
Minimum Shopping Cost with Vouchers
Overview
The goal is to reduce the total cost of $n$ products by applying vouchersCount vouchers. Each voucher halves the price of an item ($\lfloor p / 2 \rfloor$). Since we want to minimize the sum of the final prices, the most effective use of a voucher is always on the item that currently has the highest price. By reducing the largest value in the list, we maximize the absolute reduction in cost for that step. This greedy strategy must be repeated until all vouchers are exhausted or all prices become zero.
Brute Force
In a brute-force approach, for every single voucher, we scan the entire list of prices to find the maximum value, apply the voucher to it, and update the list. We repeat this process vouchersCount times.
def min_shopping_cost(prices: list[int], vouchersCount: int) -> int:
# Make a copy to avoid modifying the input
current_prices = list(prices)
for _ in range(vouchersCount):
# Find the index of the current maximum price
max_idx = 0
for i in range(1, len(current_prices)):
if current_prices[i] > current_prices[max_idx]:
max_idx = i
# If the max price is already 0, we can't reduce further
if current_prices[max_idx] == 0:
break
# Apply the voucher
current_prices[max_idx] //= 2
return sum(current_prices)
Time complexity: O(vouchersCount * n) — We iterate through the list of size $n$ to find the maximum element for every one of the $k$ vouchers. Space complexity: O(n) — We store the prices in a list of size $n$.
Optimal Approach
To improve efficiency, we need a faster way to retrieve and update the maximum element. A Max-Heap (Priority Queue) is ideal for this. In Python, the heapq module implements a Min-Heap by default, so we can simulate a Max-Heap by storing all prices as negative values.
- Push all prices into a Max-Heap.
- While
vouchersCount > 0, extract the largest price $p$. - If $p = 0$, stop (no further reductions possible).
- Apply the voucher: $p = \lfloor p / 2 \rfloor$.
- Push the updated price back into the heap and decrement
vouchersCount. - The result is the sum of all elements remaining in the heap.
import heapq
def min_shopping_cost(prices: list[int], vouchersCount: int) -> int:
# Use negative values to simulate a Max-Heap using Python's heapq (Min-Heap)
max_heap = [-p for p in prices]
heapq.heapify(max_heap)
while vouchersCount > 0 and max_heap:
# Get the largest element (most negative)
highest = -heapq.heappop(max_heap)
if highest == 0:
break
# Apply voucher and push back
new_price = highest // 2
heapq.heappush(max_heap, -new_price)
vouchersCount -= 1
return -sum(max_heap)
Time complexity: O(n + vouchersCount * log n) — Building the heap takes $O(n)$. Each voucher application involves a pop and push operation, each taking $O(\log n)$. Space complexity: O(n) — We store $n$ elements in the heap.
Why this works
The greedy choice property holds here because the function $f(x) = \lfloor x/2 \rfloor$ is monotonic, and the reduction $x - \lfloor x/2 \rfloor$ is non-decreasing with respect to $x$. In other words, applying a voucher to a larger number always yields a reduction (savings) greater than or equal to applying it to a smaller number. By consistently picking the largest available price, we ensure that each individual voucher provides the maximum possible discount at that moment.
Fast
Comments on the solution
No comments on the solution yet. Start a thread about the editorial or your own approach.
No comments yet for Minimum Shopping Cost with Vouchers. Be the first to start the thread.
No submissions recorded for this problem yet. Use Submit in the editor — each judge run is stored here.
Output
Input
Expected
Your output
Run to see your output.