You have information about n
different recipes. You are given a string array recipes
and a 2D string array ingredients
. The i<sup>th</sup>
recipe has the name recipes[i]
, and you can create it if you have all the needed ingredients from ingredients[i]
. A recipe can also be an ingredient for other recipes, i.e., ingredients[i]
may contain a string that is in recipes
.
You are also given a string array supplies
containing all the ingredients that you initially have, and you have an infinite supply of all of them.
Return *a list of all the recipes that you can create. *You may return the answer in any order.
Note that two recipes may contain each other in their ingredients.
Example 1:
Input: recipes = ["bread"], ingredients = [["yeast","flour"]], supplies = ["yeast","flour","corn"]
Output: ["bread"]
Explanation:
We can create "bread" since we have the ingredients "yeast" and "flour".
Example 2:
Input: recipes = ["bread","sandwich"], ingredients = [["yeast","flour"],["bread","meat"]], supplies = ["yeast","flour","meat"]
Output: ["bread","sandwich"]
Explanation:
We can create "bread" since we have the ingredients "yeast" and "flour".
We can create "sandwich" since we have the ingredient "meat" and can create the ingredient "bread".
Example 3:
Input: recipes = ["bread","sandwich","burger"], ingredients = [["yeast","flour"],["bread","meat"],["sandwich","meat","bread"]], supplies = ["yeast","flour","meat"]
Output: ["bread","sandwich","burger"]
Explanation:
We can create "bread" since we have the ingredients "yeast" and "flour".
We can create "sandwich" since we have the ingredient "meat" and can create the ingredient "bread".
We can create "burger" since we have the ingredient "meat" and can create the ingredients "bread" and "sandwich".
Constraints:
n == recipes.length == ingredients.length
1 <= n <= 100
1 <= ingredients[i].length, supplies.length <= 100
1 <= recipes[i].length, ingredients[i][j].length, supplies[k].length <= 10
recipes[i], ingredients[i][j]
, and supplies[k]
consist only of lowercase English letters.recipes
and supplies
combined are unique.ingredients[i]
does not contain any duplicate values.## Problem: Recipes and Ingredients
We are given a set of recipes, their ingredients, and a list of available supplies. The goal is to determine which recipes can be created given the available supplies and the ability to create other recipes that can then be used as ingredients. This problem can be solved using a graph-like approach and a form of topological sorting.
## Naive Solution (Brute Force)
The most straightforward approach would be to iterate through the recipes repeatedly. In each iteration, check if all ingredients for a recipe are available either directly from supplies or can be created. If a recipe can be created, add it to the supplies. Repeat this process until no new recipes can be created.
```python
def can_make_recipes_naive(recipes, ingredients, supplies):
can_create = set(supplies)
created_recipes = []
changed = True
while changed:
changed = False
for i in range(len(recipes)):
recipe = recipes[i]
if recipe in created_recipes:
continue
needed_ingredients = set(ingredients[i])
if needed_ingredients.issubset(can_create):
can_create.add(recipe)
created_recipes.append(recipe)
changed = True
return created_recipes
# Example Usage
recipes = ["bread", "sandwich"]
ingredients = [["yeast", "flour"], ["bread", "meat"]]
supplies = ["yeast", "flour", "meat"]
print(can_make_recipes_naive(recipes, ingredients, supplies))
The optimal approach involves a topological sort-like strategy. We can model the recipes and ingredients as a directed graph. Recipes are nodes, and a dependency from an ingredient to a recipe forms an edge. We'll use a queue to keep track of recipes that can be created. Instead of repeated checks, we maintain a count of unmet dependencies for each recipe. When a dependency is met, we decrement the count and enqueue the recipe when the count reaches zero.
from collections import deque
def can_make_recipes_optimal(recipes, ingredients, supplies):
in_degree = {}
graph = {}
for recipe in recipes:
in_degree[recipe] = 0
graph[recipe] = []
supply_set = set(supplies)
for i in range(len(recipes)):
for ingredient in ingredients[i]:
if ingredient not in supply_set:
in_degree[recipes[i]] += 1
if ingredient in graph:
graph[ingredient].append(recipes[i])
else:
graph[ingredient] = [recipes[i]]
queue = deque([recipe for recipe in recipes if in_degree[recipe] == 0])
result = []
while queue:
recipe = queue.popleft()
result.append(recipe)
for dependent_recipe in graph.get(recipe, []):
in_degree[dependent_recipe] -= 1
if in_degree[dependent_recipe] == 0:
queue.append(dependent_recipe)
return result
# Example Usage
recipes = ["bread", "sandwich"]
ingredients = [["yeast", "flour"], ["bread", "meat"]]
supplies = ["yeast", "flour", "meat"]
print(can_make_recipes_optimal(recipes, ingredients, supplies))
can_create
set and the created_recipes
list.in_degree
dictionary and the adjacency list (graph
).ingredients[i]
does not contain any duplicate values, but the algorithm must still handle possible duplicate ingredients from the supplies list.Let's consider the example:
`recipes = [