Facebook Pixel

2706. Buy Two Chocolates

Problem Description

You are given an array prices where each element represents the price of a chocolate in a store. You also have an initial amount of money represented by the integer money.

Your task is to buy exactly two chocolates such that:

  1. You must have non-negative money left after the purchase (you cannot go into debt)
  2. You want to minimize the total cost of the two chocolates

The goal is to return the amount of money you'll have left after buying the two chocolates. If it's impossible to buy any two chocolates without going into debt, return your original money amount.

For example:

  • If prices = [1, 2, 2] and money = 3, you can buy chocolates costing 1 and 2, spending 3 total, leaving you with 3 - 3 = 0 money
  • If prices = [3, 2, 3] and money = 3, the minimum cost for two chocolates is 2 + 3 = 5, which exceeds your money, so you return 3

The solution sorts the array to find the two cheapest chocolates (prices[0] and prices[1]), calculates their total cost, and returns either the leftover money if affordable or the original money if not.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

To minimize the sum of two chocolates, we need to pick the two cheapest chocolates available. Think of it this way: if we have chocolates with prices [5, 1, 3, 2], picking any combination other than the two smallest values would result in a higher total cost.

The key insight is that we don't need to check all possible pairs of chocolates. Since we want the minimum sum, we simply need the two smallest values in the array. The most straightforward way to find these is by sorting the array in ascending order - this puts the cheapest chocolate at index 0 and the second cheapest at index 1.

Once we have the two cheapest chocolates, we calculate their total cost as prices[0] + prices[1]. Now we face a simple decision:

  • If cost > money: We can't afford even the cheapest pair, so we buy nothing and keep our original money
  • If cost <= money: We can afford them, so we buy them and return money - cost as our leftover

This greedy approach works because there's no scenario where choosing more expensive chocolates would give us a better outcome - we always want to minimize our spending to maximize our leftover money.

Learn more about Greedy and Sorting patterns.

Solution Approach

The solution uses a sorting-based greedy approach to find the minimum cost for buying two chocolates.

Step-by-step implementation:

  1. Sort the prices array: We call prices.sort() to arrange all chocolate prices in ascending order. After sorting, prices[0] contains the cheapest chocolate and prices[1] contains the second cheapest chocolate.

  2. Calculate minimum cost: We compute cost = prices[0] + prices[1]. This gives us the minimum possible sum for buying any two chocolates from the store.

  3. Check affordability and return result: We use a conditional expression to determine what to return:

    • If money < cost: We cannot afford even the cheapest pair of chocolates, so we return money (keeping all our money)
    • Otherwise: We can afford the chocolates, so we return money - cost (the leftover amount after purchase)

Time Complexity: O(n log n) where n is the length of the prices array, dominated by the sorting operation.

Space Complexity: O(1) or O(n) depending on the sorting algorithm implementation (Python's Timsort uses O(n) space in the worst case).

The beauty of this solution lies in its simplicity - by sorting first, we immediately have access to the two minimum values without needing to track them manually or iterate through all possible pairs.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with prices = [5, 3, 1, 4, 2] and money = 7.

Step 1: Sort the prices array

  • Original array: [5, 3, 1, 4, 2]
  • After sorting: [1, 2, 3, 4, 5]
  • Now prices[0] = 1 (cheapest) and prices[1] = 2 (second cheapest)

Step 2: Calculate minimum cost

  • cost = prices[0] + prices[1] = 1 + 2 = 3
  • This is the minimum possible sum for any two chocolates

Step 3: Check affordability and return result

  • We have money = 7 and cost = 3
  • Since 7 >= 3, we can afford these chocolates
  • Money left after purchase: 7 - 3 = 4
  • Return: 4

Let's trace through another example where we can't afford any chocolates: prices = [10, 8, 9] and money = 15.

Step 1: Sort โ†’ [8, 9, 10] Step 2: Calculate cost โ†’ 8 + 9 = 17 Step 3: Check affordability โ†’ Since 15 < 17, we can't afford even the cheapest pair Return: 15 (keep all our money)

The key insight is that sorting immediately gives us the optimal pair without checking all combinations. Any other pair would cost more than prices[0] + prices[1].

Solution Implementation

1class Solution:
2    def buyChoco(self, prices: List[int], money: int) -> int:
3        """
4        Determines the remaining money after buying two cheapest chocolates.
5        If cannot afford both, returns the original money amount.
6      
7        Args:
8            prices: List of chocolate prices
9            money: Available money to spend
10          
11        Returns:
12            Remaining money after purchase, or original money if cannot afford
13        """
14        # Sort prices in ascending order to get the two cheapest chocolates
15        prices.sort()
16      
17        # Calculate the total cost of the two cheapest chocolates
18        total_cost = prices[0] + prices[1]
19      
20        # If we don't have enough money, return the original amount
21        # Otherwise, return the remaining money after purchase
22        if money < total_cost:
23            return money
24        else:
25            return money - total_cost
26
1class Solution {
2    /**
3     * Calculates the remaining money after buying two chocolates with minimum prices.
4     * If the total cost exceeds available money, returns the original money amount.
5     * 
6     * @param prices Array of chocolate prices
7     * @param money Available money to spend
8     * @return Remaining money after purchase, or original money if purchase not possible
9     */
10    public int buyChoco(int[] prices, int money) {
11        // Sort the prices array in ascending order to find the two cheapest chocolates
12        Arrays.sort(prices);
13      
14        // Calculate the total cost of the two cheapest chocolates
15        int totalCost = prices[0] + prices[1];
16      
17        // Check if we have enough money to buy both chocolates
18        // If not enough money, return the original amount
19        // Otherwise, return the remaining money after purchase
20        return money < totalCost ? money : money - totalCost;
21    }
22}
23
1class Solution {
2public:
3    int buyChoco(vector<int>& prices, int money) {
4        // Sort the prices array in ascending order to find the two cheapest chocolates
5        sort(prices.begin(), prices.end());
6      
7        // Calculate the total cost of buying the two cheapest chocolates
8        int totalCost = prices[0] + prices[1];
9      
10        // If we don't have enough money, return the original amount
11        // Otherwise, return the remaining money after purchase
12        return (money < totalCost) ? money : (money - totalCost);
13    }
14};
15
1/**
2 * Calculates the leftover money after buying two chocolates with minimum cost.
3 * If cannot afford the two cheapest chocolates, returns the original money.
4 * 
5 * @param prices - Array of chocolate prices
6 * @param money - Available money to spend
7 * @returns Leftover money after purchase, or original money if cannot afford
8 */
9function buyChoco(prices: number[], money: number): number {
10    // Sort prices in ascending order to find the two cheapest chocolates
11    prices.sort((a: number, b: number) => a - b);
12  
13    // Calculate the total cost of the two cheapest chocolates
14    const totalCost: number = prices[0] + prices[1];
15  
16    // Return leftover money if affordable, otherwise return original money
17    return money < totalCost ? money : money - totalCost;
18}
19

Time and Space Complexity

The time complexity is O(n ร— log n), where n is the length of the array prices. This is because the sort() method in Python uses Timsort algorithm, which has a worst-case and average-case time complexity of O(n ร— log n). After sorting, accessing the first two elements and performing the arithmetic operations take O(1) time, so the overall time complexity is dominated by the sorting operation.

The space complexity is O(log n). While the sorting is performed in-place (modifying the original array without creating a new one), the Timsort algorithm used by Python's sort() method requires O(log n) space for the recursion stack during the sorting process. The remaining operations use only O(1) additional space for storing the cost variable.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Not Handling Arrays with Fewer Than Two Elements

The current solution assumes the array has at least two elements. If prices has 0 or 1 element, accessing prices[0] and prices[1] will raise an IndexError.

Solution: Add a length check at the beginning:

def buyChoco(self, prices: List[int], money: int) -> int:
    # Edge case: need at least 2 chocolates to buy
    if len(prices) < 2:
        return money
  
    prices.sort()
    total_cost = prices[0] + prices[1]
    return money if money < total_cost else money - total_cost

2. Modifying the Original Array

The sort() method modifies the input array in-place, which could be problematic if the caller expects the original array to remain unchanged or if the array is used elsewhere.

Solution: Use sorted() instead to create a new sorted array:

def buyChoco(self, prices: List[int], money: int) -> int:
    sorted_prices = sorted(prices)
    total_cost = sorted_prices[0] + sorted_prices[1]
    return money if money < total_cost else money - total_cost

3. Inefficient for Finding Just Two Minimum Values

Sorting the entire array takes O(n log n) time when we only need the two smallest values, which can be found in O(n) time.

Solution: Use a linear scan to find the two minimum values:

def buyChoco(self, prices: List[int], money: int) -> int:
    min1 = min2 = float('inf')
  
    for price in prices:
        if price < min1:
            min2 = min1
            min1 = price
        elif price < min2:
            min2 = price
  
    total_cost = min1 + min2
    return money if money < total_cost else money - total_cost

4. Not Considering Integer Overflow

While less common in Python due to arbitrary precision integers, in other languages or with very large values, adding two prices could cause overflow.

Solution: Check for potential overflow before addition:

def buyChoco(self, prices: List[int], money: int) -> int:
    prices.sort()
  
    # Check if addition would exceed money before computing
    if prices[0] > money or prices[1] > money - prices[0]:
        return money
  
    total_cost = prices[0] + prices[1]
    return money - total_cost
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the following shows the order of node visit in a Breadth-first Search?


Recommended Readings

Want a Structured Path to Master System Design Too? Donโ€™t Miss This!

Load More