Talentd
FleetCode
Make and follow sheets.Sign in

Find All Possible Recipes from Given Supplies solution and explanation

MediumArrayGraphHash TableString7 min read56.8% acceptanceUpdated 9 Apr 2026
Find All Possible Recipes from Given Supplies - Leetcode 2115 - PythonNeetCodeIO · 19:55 · 12K viewsWatch on YouTube
9 more videos on this problem
  1. Find All Possible Recipes from Given Supplies - Leetcode 2115 - PythonNeetCodeIO · 19:55 · 12K views
  2. Find All Possible Recipes from Given Supplies | Brute Force | Optimal | Leetcode 2115codestorywithMIK · 37:22 · 10K views
  3. FIND ALL RECIPES FROM GIVEN SUPPLIES | LEETCODE 2115 | PYTHON TOPOLOGICAL SORT SOLUTIONCracking FAANG · 17:20 · 6K views
  4. Find All Possible Recipes from Given Supplies | Leetcode 2115Techdose · 20:00 · 4K views
  5. 2115. Find All Possible Recipes from Given Supplies | Topological SortAryan Mittal · 11:53 · 3K views
  6. Find All Possible Recipes from Given Supplies | LeetCode 2115 | Topological Sort | Python SolutionMad Dev Canvas · 14:02 · 2K views
  7. 2115. Find All Possible Recipes from Given Supplies (Leetcode Medium)Programming Live with Larry · 6:14 · 2K views
  8. LEETCODE - 2115. Find All Possible Recipes from Given Supplies | Python | DFS | Recursioncodegreen · 19:01 · 796 views
  9. leetcode 2115 Find All Possible Recipes from Given SuppliesMath Geeks · 4:35 · 669 views
  10. Leetcode 2115. Find All Possible Recipes from Given Supplies (topological sort)LetsCode · 11:41 · 140 views

The problem

You have information about n different recipes. You are given a string array recipes and a 2D string array ingredients. The ith recipe has the name recipes[i], and you can create it if you have all the needed ingredients from ingredients[i]. Ingredients to a recipe may need to be created from 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.
  • All the values of recipes and supplies combined are unique.
  • Each ingredients[i] does not contain any duplicate values.

Approach overview

Problem Overview: You are given a list of recipes, their required ingredients, and a list of initial supplies. Some ingredients may themselves be recipes. The task is to determine every recipe you can ultimately prepare by resolving these dependencies.

Approach 1: Backtracking with Memoization (DFS) (Time: O(N * K), Space: O(N))

This approach treats the problem as dependency resolution using recursion. For each recipe, run a DFS to check whether all its ingredients can be produced. If an ingredient exists in the supply set, it is immediately usable. If it is another recipe, recursively attempt to build it. Memoization caches whether a recipe is possible or impossible, preventing repeated work across different dependency chains.

The key insight is that recipes form a dependency graph. DFS explores these dependencies until reaching either base supplies or a missing ingredient. Memoization avoids recomputing the same recipe multiple times. This approach works well when the dependency depth is small, but recursive traversal still introduces overhead compared to iterative graph processing.

Relevant concepts include graph traversal and efficient lookups with a hash table.

Approach 2: Topological Sort using Kahn's Algorithm (Time: O(N + E), Space: O(N + E))

This is the optimal approach. Model the problem as a directed graph where ingredients point to recipes that depend on them. Track the number of missing ingredients for each recipe using an indegree counter. All initial supplies are pushed into a queue since they are already available.

Process the queue using Kahn's algorithm. When a supply or completed recipe becomes available, iterate over the recipes that depend on it and decrement their indegree. Once a recipe's indegree reaches zero, every required ingredient is available, so that recipe can be produced and added to the queue as a new supply.

The key insight is that recipes behave like nodes in a dependency DAG. Topological sorting naturally processes them in a valid production order. Each ingredient and dependency edge is processed once, giving linear complexity relative to nodes and edges. This method relies heavily on topological sort and adjacency lists built with arrays and hash maps.

Recommended for interviews: The topological sort solution using Kahn's algorithm is what most interviewers expect. It demonstrates strong understanding of dependency graphs and efficient processing of prerequisites. DFS with memoization still shows solid reasoning and works well conceptually, but the topological approach scales better and is the canonical solution for dependency problems.

Approach 1: Topological Sort using Kahn's Algorithm

This approach uses graph theory to solve the problem. Each recipe and ingredient is considered a node. An edge from node A to node B indicates that node B is needed to create node A. We can then perform a topological sort utilizing Kahn's Algorithm to determine the order in which we can create the recipes.

from collections import defaultdict, deque

def findAllRecipes(recipes, ingredients, supplies):
    graph = defaultdict(list)
    indegree = defaultdict(int)
    for r, ing in zip(recipes, ingredients):
        for i in ing:
            graph[i].append(r)
            indegree[r] += 1

    queue = deque(supplies)
    possible_recipes = set(supplies)

    while queue:
        item = queue.popleft()

        for neighbor in graph[item]:
            indegree[neighbor] -= 1
            if indegree[neighbor] == 0:
                possible_recipes.add(neighbor)
                queue.append(neighbor)

    return [r for r in recipes if r in possible_recipes]

# Example Usage
# print(findAllRecipes(["bread"], [["yeast","flour"]], ["yeast","flour","corn"]))
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <queue>

std::vector<std::string> findAllRecipes(std::vector<std::string>& recipes, std::vector<std::vector<std::string>>& ingredients, std::vector<std::string>& supplies) {
    std::unordered_map<std::string, std::vector<std::string>> graph;
    std::unordered_map<std::string, int> indegree;
    std::queue<std::string> q;
    std::unordered_set<std::string> supplies_set(supplies.begin(), supplies.end());

    for (int i = 0; i < recipes.size(); ++i) {
        for (const std::string& ing : ingredients[i]) {
            graph[ing].push_back(recipes[i]);
            indegree[recipes[i]]++;
        }
    }

    for (const std::string& s : supplies) {
        q.push(s);
    }

    std::vector<std::string> result;
    while (!q.empty()) {
        std::string item = q.front(); q.pop();
        if (supplies_set.find(item) == supplies_set.end()) {
            result.push_back(item);
        }
        for (const std::string& neighbor : graph[item]) {
            if (--indegree[neighbor] == 0) {
                q.push(neighbor);
                supplies_set.insert(neighbor);
            }
        }
    }

    return result;
}

int main() {
    std::vector<std::string> recipes = {"bread", "sandwich"};
    std::vector<std::vector<std::string>> ingredients = {{"yeast", "flour"}, {"bread", "meat"}};
    std::vector<std::string> supplies = {"yeast", "flour", "meat"};
    std::vector<std::string> creatable_recipes = findAllRecipes(recipes, ingredients, supplies);
    for (const std::string& recipe : creatable_recipes) {
        std::cout << recipe << " ";
    }
    return 0;
}

In this implementation, we first build the graph and compute the in-degrees of each recipe. We fill the queue with our initial supplies and perform a BFS. We decrement the in-degree of the neighboring nodes when visiting each node, and if a neighbor's in-degree becomes zero, it means that all ingredients to make it are available, so we add it to the queue.

Complexity

Time Complexity: O(n + m), where n is the number of recipes and m is the total number of ingredients.
Space Complexity: O(n + m), due to the graph and in-degree storage.

Try this approach in the editor

Approach 2: Backtracking with Memoization

This approach involves trying to create each recipe by checking if all its ingredients are available or can be created from other recipes. We use memoization to store the results of subproblems, avoiding redundant calculations.

import java.util.*;

public class RecipeFinder {
    public List<String> findAllRecipes(String[] recipes, List<List<String>> ingredients, String[] supplies) {
        Set<String> suppliesSet = new HashSet<>(Arrays.asList(supplies));
        Map<String, Boolean> memo = new HashMap<>();

        List<String> result = new ArrayList<>();
        for (int i = 0; i < recipes.length; i++) {
            if (canCreate(recipes[i], ingredients, recipes, suppliesSet, memo)) {
                result.add(recipes[i]);
            }
        }

        return result;
    }

    private boolean canCreate(String recipe, List<List<String>> ingredients, String[] recipes, Set<String> supplies, Map<String, Boolean> memo) {
        if (supplies.contains(recipe)) return true;
        if (memo.containsKey(recipe)) return memo.get(recipe);

        int recipeIndex = getRecipeIndex(recipe, recipes);
        if (recipeIndex == -1) return false;

        for (String ing : ingredients.get(recipeIndex)) {
            if (!canCreate(ing, ingredients, recipes, supplies, memo)) {
                memo.put(recipe, false);
                return false;
            }
        }

        memo.put(recipe, true);
        supplies.add(recipe); // Now we can create this recipe
        return true;
    }

    private int getRecipeIndex(String recipe, String[] recipes) {
        for (int i = 0; i < recipes.length; i++) {
            if (recipes[i].equals(recipe)) return i;
        }
        return -1;
    }

    public static void main(String[] args) {
        RecipeFinder finder = new RecipeFinder();
        String[] recipes = { "bread", "sandwich" };
        List<List<String>> ingredients = Arrays.asList(
            Arrays.asList("yeast", "flour"),
            Arrays.asList("bread", "meat")
        );
        String[] supplies = { "yeast", "flour", "meat" };
        System.out.println(finder.findAllRecipes(recipes, ingredients, supplies));
    }
}
using System;
using System.Collections.Generic;

public class Solution {
    public IList<string> FindAllRecipes(string[] recipes, IList<IList<string>> ingredients, string[] supplies) {
        var supplySet = new HashSet<string>(supplies);
        var memo = new Dictionary<string, bool>();

        List<string> result = new List<string>();
        for (int i = 0; i < recipes.Length; i++) {
            if (CanCreate(recipes[i], ingredients, recipes, supplySet, memo)) {
                result.Add(recipes[i]);
            }
        }
        return result;
    }

    private bool CanCreate(string recipe, IList<IList<string>> ingredients, string[] recipes, HashSet<string> supplies, Dictionary<string, bool> memo) {
        if (supplies.Contains(recipe)) return true;
        if (memo.ContainsKey(recipe)) return memo[recipe];

        int recipeIndex = Array.IndexOf(recipes, recipe);
        if (recipeIndex == -1) return false;

        foreach (string ingredient in ingredients[recipeIndex]) {
            if (!CanCreate(ingredient, ingredients, recipes, supplies, memo)) {
                memo[recipe] = false;
                return false;
            }
        }

        memo[recipe] = true;
        supplies.Add(recipe);
        return true;
    }

    public static void Main(string[] args) {
        var solution = new Solution();
        var recipes = new string[] { "bread", "sandwich" };
        var ingredients = new List<IList<string>> {
            new List<string> { "yeast", "flour" },
            new List<string> { "bread", "meat" }
        };
        var supplies = new string[] { "yeast", "flour", "meat" };
        var creatableRecipes = solution.FindAllRecipes(recipes, ingredients, supplies);
        Console.WriteLine(string.Join(", ", creatableRecipes));
    }
}

This implementation checks each recipe to see if it can be created using a recursive backtracking approach. It covers all subproblems using memoization, thereby improving efficiency. An ingredient is considered ready if it can be created from available supplies, its own recipe, or if it already appears in supplies.

Complexity

Time Complexity: O(n * m), where n is the number of recipes and m is the average number of ingredients.
Space Complexity: O(n + m), due to the auxiliary data structures used for memoization and recursion stack.

Try this approach in the editor

Approach 3: Default Approach

func findAllRecipes(recipes []string, ingredients [][]string, supplies []string) []string {
	g := map[string][]string{}
	indeg := map[string]int{}
	for i, a := range recipes {
		for _, b := range ingredients[i] {
			g[b] = append(g[b], a)
		}
		indeg[a] = len(ingredients[i])
	}
	q := []string{}
	for _, s := range supplies {
		q = append(q, s)
	}
	ans := []string{}
	for len(q) > 0 {
		for n := len(q); n > 0; n-- {
			i := q[0]
			q = q[1:]
			for _, j := range g[i] {
				indeg[j]--
				if indeg[j] == 0 {
					ans = append(ans, j)
					q = append(q, j)
				}
			}
		}
	}
	return ans
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Topological Sort using Kahn's Algorithm

Time Complexity: O(n + m), where n is the number of recipes and m is the total number of ingredients.
Space Complexity: O(n + m), due to the graph and in-degree storage.

Backtracking with Memoization

Time Complexity: O(n * m), where n is the number of recipes and m is the average number of ingredients.
Space Complexity: O(n + m), due to the auxiliary data structures used for memoization and recursion stack.

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Backtracking with Memoization (DFS)O(N * K)O(N)Useful for understanding dependency resolution or when recursion is easier to implement.
Topological Sort (Kahn's Algorithm)O(N + E)O(N + E)Best for large dependency graphs and the expected optimal interview solution.

Frequently asked questions

Is Find All Possible Recipes from Given Supplies easy or hard?

The problem is rated Medium on LeetCode with an acceptance rate around 56%. The difficulty comes from recognizing the dependency graph and applying topological sorting. Once modeled correctly, the algorithm is straightforward to implement.

Find All Possible Recipes from Given Supplies Python/Java solution

Python solutions usually implement Kahn's algorithm using collections.deque for the queue and defaultdict for the adjacency list. Java implementations rely on HashMap, ArrayList, and a Queue such as LinkedList. Both versions maintain indegree counts and push recipes into the queue once all ingredients are satisfied.

How to solve Find All Possible Recipes from Given Supplies in O(N + E)?

Build a graph mapping ingredients to recipes that depend on them. Track the number of missing ingredients for each recipe using an indegree array. Push all initial supplies into a queue, then repeatedly process available items and reduce indegrees of dependent recipes. When a recipe's indegree reaches zero, add it to the queue and mark it as producible.

What is the best approach for Find All Possible Recipes from Given Supplies?

The most efficient solution uses topological sorting with Kahn's algorithm. Recipes and ingredients form a dependency graph where each ingredient contributes to a recipe's indegree count. Starting from the available supplies, process nodes in BFS order and unlock recipes once all required ingredients are available. This runs in O(N + E) time.

Is Find All Possible Recipes from Given Supplies asked at Google/Amazon/Meta?

Dependency resolution and topological sorting problems frequently appear in interviews at companies like Google, Amazon, and Meta. Variations include course scheduling, build systems, and package dependency resolution. This problem tests understanding of DAG processing and graph traversal.

What data structure is used in Find All Possible Recipes from Given Supplies?

The solution typically uses an adjacency list to represent the graph, a hash map for fast ingredient-to-recipe lookups, an indegree array to track remaining dependencies, and a queue for BFS processing during Kahn's topological sort.

What is the time complexity of Find All Possible Recipes from Given Supplies?

The optimal topological sort approach runs in O(N + E) time, where N is the number of recipes and E is the total number of ingredient dependencies. Each edge in the dependency graph is processed once when updating indegrees. Space complexity is also O(N + E) for the adjacency list and queue.

Comments

Now write it yourselfClose this page and solve Find All Possible Recipes from Given Supplies in the editor, without looking.
Practise Find All Possible Recipes from Given Supplies