2115. Find All Possible Recipes from Given Supplies (Topological Sort)¶
Edited by Charles
Medium · Python · Graph
Problem
Read the original problem on LeetCode.
The official page contains the problem statement, examples, and constraints.
Explanation, examples & other approaches
Core idea
Use Topological Sort + Kahn's Algorithm.
Each recipe depends on several ingredients.
Original study notes follow, including intermediate snippets and earlier attempts.
Idea¶
Use Topological Sort + Kahn's Algorithm.
Each recipe depends on several ingredients.
We can think of:
as a directed edge.
For example:
The key idea is:
Start with all available supplies. Whenever all ingredients of a recipe become available, we can make that recipe and use it as a new supply.
This is very similar to LeetCode 207 / 210.
Graph¶
Define:
as:
All recipes that require this ingredient.
We build the graph using:
For example:
The graph becomes:
So:
graph["yeast"] = ["bread"]
graph["flour"] = ["bread"]
graph["bread"] = ["sandwich"]
graph["meat"] = ["sandwich"]
Why defaultdict(list)?¶
We define:
If a key does not exist, defaultdict(list) automatically creates an empty list.
For example:
If "flour" does not exist yet, Python automatically creates:
and then appends "bread".
So:
This avoids writing:
Memory:
defaultdict(list)→ missing key automatically gets[].
Indegree¶
Define:
as:
The number of ingredients that are still required to make this recipe.
Initially:
For example:
so:
Similarly:
so:
Initialize the Queue¶
Unlike normal Kahn's Algorithm, we do not start with nodes whose indegree is 0.
Instead, we already have some materials available:
So initialize:
For example:
then:
These are the materials we can use immediately.
BFS / Kahn's Algorithm¶
Each time we take an available material:
We check which recipes require this material:
Since this ingredient is now available, that recipe has one fewer missing ingredient:
If:
then all ingredients required by this recipe are available.
Therefore, we can make it:
Recipe Becomes a New Supply¶
This is the most important part of the problem.
After making a recipe, the recipe itself can be used as an ingredient for another recipe.
Therefore:
For example:
Once bread is created, we add it to the queue:
Then "bread" can unlock "sandwich".
So the process continues until no more recipes can be created.
Hand Simulation¶
Suppose:
recipes = ["bread", "sandwich"]
ingredients = [
["yeast", "flour"],
["bread", "meat"]
]
supplies = ["yeast", "flour", "meat"]
Initially:
Process yeast¶
yeast is required by bread:
State:
Process flour¶
flour is also required by bread:
Now all ingredients of bread are available.
So:
State:
Process meat¶
meat is required by sandwich:
State:
Process bread¶
bread is also required by sandwich:
Now sandwich can be created:
Finally, processing sandwich unlocks nothing else.
Result:
Why Does This Handle Cycles?¶
Suppose:
Then:
If neither A nor B is initially available in supplies, neither recipe can have its indegree reduced to 0.
Therefore, neither recipe will ever enter the queue.
So recipes involved in an unresolved dependency cycle are automatically excluded.
Connection to LeetCode 207 / 210¶
The structure is almost the same as Course Schedule.
LeetCode 210¶
indegree[course] means:
How many prerequisites are still required?
LeetCode 2115¶
indegree[recipe] means:
How many ingredients are still required?
The major difference is the initial queue:
And in 2115, once a recipe is created:
because that recipe becomes a new available material.
Key Insight¶
Treat ingredients as prerequisites and recipes as courses.
Whenever an available material satisfies one dependency:
When:
the recipe can be created and becomes a new supply.
Memory:
Supplies unlock recipes, and completed recipes become new supplies.
Complexity¶
Let:
R= number of recipesE= total number of ingredient dependencies
Building the graph takes:
Each dependency is processed at most once during BFS:
Therefore:
Study record
| Field | Value |
|---|---|
| Attempts | 1 |
| Mastery | ❚ |
| The Latest Attempt | August 27, 2026 |
Python solution¶
from collections import defaultdict, deque
class Solution:
def findAllRecipes(self, recipes: List[str], ingredients: List[List[str]], supplies: List[str]) -> List[str]:
graph = defaultdict(list)
indegree = {}
for i in range(len(recipes)):
recipe = recipes[i]
indegree[recipe] = len(ingredients[i])
for ingredient in ingredients[i]:
graph[ingredient].append(recipe)
queue = deque(supplies)
res = []
while queue:
material = queue.popleft()
for recipe in graph[material]:
indegree[recipe] -= 1
if indegree[recipe] == 0:
res.append(recipe)
queue.append(recipe)
return res