Design menu DP and optimize for three items
Company: Airbnb
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Technical Screen
Quick Answer: This question evaluates understanding of dynamic programming, search with memoization, multidimensional state representation, and pruning/dominance reasoning for combinatorial cost minimization under constraints.
Constraints
- 1 <= n <= 6
- 0 <= m <= 100 (number of offers)
- 0 <= needs[i] <= 10
- 1 <= prices[i] <= 10^4
- 0 <= offer quantities and offer price <= 10^6
- Each offer is length n+1: first n entries are quantities, last is price
- No over-purchasing allowed: total bought for each item must equal needs[i]
Solution
from functools import lru_cache
def min_menu_cost(prices: list[int], offers: list[list[int]], needs: list[int]) -> int:
n = len(prices)
assert len(needs) == n, "needs must match number of prices"
# Preprocess offers: keep valid and useful ones
filtered = []
for off in offers:
if not isinstance(off, list) or len(off) != n + 1:
continue
q = tuple(max(0, int(x)) for x in off[:-1])
cost = int(off[-1])
# Skip zero-quantity offers
if all(qi == 0 for qi in q):
continue
# Offers that require more than total need in any dimension can never be used (no overbuying)
if any(q[i] > needs[i] for i in range(n)):
continue
# Prune dominated offers (no cheaper than buying items separately)
base = sum(q[i] * prices[i] for i in range(n))
if cost >= base:
continue
filtered.append((q, cost))
needs_t = tuple(needs)
@lru_cache(maxsize=None)
def dfs(state: tuple) -> int:
# Cost of buying remaining items individually
base_cost = sum(state[i] * prices[i] for i in range(n))
best = base_cost
for q, c in filtered:
# Can we apply this offer?
for i in range(n):
if q[i] > state[i]:
break
else:
next_state = tuple(state[i] - q[i] for i in range(n))
cand = c + dfs(next_state)
if cand < best:
best = cand
return best
return dfs(needs_t)
Explanation
Time complexity: O(m * Π_i (needs[i] + 1)), where m is the number of remaining offers after pruning. Space complexity: O(Π_i (needs[i] + 1)) for memoization, plus O(m + n) for offers and parameters.
Hints
- Think of the remaining needs as a state. Use DFS with memoization where the key is a tuple of remaining quantities.
- The base case for any state is buying all remaining items as singles.
- Prune offers that cost at least as much as buying their quantities individually, or that exceed initial needs in any dimension.
- If the order involves at most three items, a 3D DP table over the three quantities yields O((a+1)(b+1)(c+1) * m) time.