Given a menu represented as a map from item name to price and a target budget, return all combinations of menu item names whose total price equals the budget. Items can be chosen multiple times unless the menu semantics restrict repetitions (this version allows repeats — each menu item is unlimited).
Prices should ideally be treated as integers (for example, cents) to avoid floating-point rounding issues.
The standard solution is backtracking (depth-first search) analogous to Combination Sum: convert the map into a list of (name, price) pairs sorted by price, then explore combinations by iterating choices and recursing with decreased remaining budget.
At each step pick a menu item (possibly the same as prior picks) and subtract its price from the remaining budget. If the remaining budget becomes 0, the current combination is valid. If it becomes negative, backtrack. Sorting items by price allows early pruning.
classSolution {
dataclassItem(val name: String, val price: Int)
funmenuCombinations(items: List<Item>, budget: Int): List<List<String>> {
val sorted = items.sortedBy { it.price }
val ans = mutableListOf<List<String>>()
val curr = mutableListOf<String>()
fundfs(idx: Int, rem: Int) {
if (rem ==0) { ans.add(curr.toList()); return }
if (rem < 0) returnfor (i in idx until sorted.size) {
val it = sorted[i]
if (it.price > rem) break curr.add(it.name)
dfs(i, rem - it.price)
curr.removeAt(curr.lastIndex)
}
}
dfs(0, budget)
return ans
}
}
⏰ Time complexity: O(m * Π_{i=0..m-1} s_i) where m is the number of distinct menu items and s_i is branching due to repeated choices — more informally, it’s proportional to the number of valid and explored combinations; sorting adds O(m log m).
🧺 Space complexity: O(k * L) to store output where k is number of combinations and L average length; auxiliary recursion stack O(m).