{x}
blog image

Closest Dessert Cost

You would like to make dessert and are preparing to buy the ingredients. You have n ice cream base flavors and m types of toppings to choose from. You must follow these rules when making your dessert:

  • There must be exactly one ice cream base.
  • You can add one or more types of topping or have no toppings at all.
  • There are at most two of each type of topping.

You are given three inputs:

  • baseCosts, an integer array of length n, where each baseCosts[i] represents the price of the ith ice cream base flavor.
  • toppingCosts, an integer array of length m, where each toppingCosts[i] is the price of one of the ith topping.
  • target, an integer representing your target price for dessert.

You want to make a dessert with a total cost as close to target as possible.

Return the closest possible cost of the dessert to target. If there are multiple, return the lower one.

 

Example 1:

Input: baseCosts = [1,7], toppingCosts = [3,4], target = 10
Output: 10
Explanation: Consider the following combination (all 0-indexed):
- Choose base 1: cost 7
- Take 1 of topping 0: cost 1 x 3 = 3
- Take 0 of topping 1: cost 0 x 4 = 0
Total: 7 + 3 + 0 = 10.

Example 2:

Input: baseCosts = [2,3], toppingCosts = [4,5,100], target = 18
Output: 17
Explanation: Consider the following combination (all 0-indexed):
- Choose base 1: cost 3
- Take 1 of topping 0: cost 1 x 4 = 4
- Take 2 of topping 1: cost 2 x 5 = 10
- Take 0 of topping 2: cost 0 x 100 = 0
Total: 3 + 4 + 10 + 0 = 17. You cannot make a dessert with a total cost of 18.

Example 3:

Input: baseCosts = [3,10], toppingCosts = [2,5], target = 9
Output: 8
Explanation: It is possible to make desserts with cost 8 and 10. Return 8 as it is the lower cost.

 

Constraints:

  • n == baseCosts.length
  • m == toppingCosts.length
  • 1 <= n, m <= 10
  • 1 <= baseCosts[i], toppingCosts[i] <= 104
  • 1 <= target <= 104

Solution Explanation

This problem asks to find the closest dessert cost to a target price, given base costs and topping costs. The solution involves exploring all possible combinations of base and toppings, and finding the closest cost to the target.

Approach

The solution uses a depth-first search (DFS) or backtracking approach to efficiently explore all possible dessert combinations. The algorithm proceeds in two main steps:

  1. Generate Topping Combinations: A recursive DFS function is used to generate all possible topping combinations. The function iterates through each topping, adding 0, 1, or 2 of each topping to the current dessert cost. This ensures that at most two of each topping type are used.

  2. Find Closest Cost: The main function iterates through all base costs. For each base cost, it combines it with each topping combination generated in step 1. It then finds the combination that results in a dessert cost closest to the target. The code maintains both the difference from the target and the actual cost, ensuring that the lower cost is chosen in case of a tie in the difference. Binary search could be used to optimize the search for the closest combination.

Time and Space Complexity

  • Time Complexity: The time complexity is dominated by the generation of topping combinations. For m topping types, there are 3m possible combinations (0, 1, or 2 of each topping). The process also iterates through n base costs. Therefore, the time complexity is O(n * 3m). In the optimized solution using binary search, the search becomes O(log(3m)) instead of O(3m) which simplifies it to O(n*m)

  • Space Complexity: The space complexity is O(3m) in the worst case due to the storage of topping combinations. The recursive DFS calls create a recursion stack that also contributes to space complexity but that is typically bounded by m.

Code Explanation (Python)

The Python solution implements the above approach:

class Solution:
    def closestCost(self, baseCosts, toppingCosts, target):
        def dfs(i, current_cost):
            if i == len(toppingCosts):
                topping_combinations.append(current_cost)
                return
            dfs(i + 1, current_cost)  # Don't add this topping
            dfs(i + 1, current_cost + toppingCosts[i]) # Add one of this topping
            dfs(i + 1, current_cost + 2 * toppingCosts[i]) #Add two of this topping
 
        topping_combinations = []
        dfs(0, 0)
        topping_combinations.sort() #Sorting for efficient search
 
        closest_cost = float('inf')
        min_diff = float('inf')
 
        for base_cost in baseCosts:
            for topping_cost in topping_combinations:
                total_cost = base_cost + topping_cost
                diff = abs(target - total_cost)
                if diff < min_diff:
                    min_diff = diff
                    closest_cost = total_cost
                elif diff == min_diff and total_cost < closest_cost:
                    closest_cost = total_cost
        return closest_cost
 

The dfs function recursively explores topping combinations. The main part of the function then iterates through base costs and topping combinations, finding the closest cost to the target while handling ties appropriately. Note that this solution is not optimized with binary search and the time complexity is O(n * 3m)

Other languages (Java, C++, Go, Javascript) follow similar logic, adjusting syntax and data structures as needed for each language. The optimized solutions using binary search are also provided in those languages.