find-all-possible-recipes-from-given-supplies.py (2595B)
1 struct Node{ 2 size_t inDegree; 3 string name; 4 bool isRecipe; 5 vector<string> requiredBy; 6 }; 7 8 9 class Solution { 10 public: 11 vector<string> findAllRecipes(vector<string>& recipes, vector<vector<string>>& ingredients, vector<string>& supplies) { 12 13 // n different recipes (recipes.size()) 14 // ingredients[i] are ingredients to make recipes[i] 15 // works if we have all of the ingredients in supplies 16 // a recipe can be an ingredient for other recipes too 17 18 // approach: 19 // this seems like a topological sort problem 20 // to add a recipe to the list, all of the priors (ingredients) 21 // must be in the sorted list. 22 23 // concretely: 24 // use khan's algorithm 25 // add all vertices with an in-degree of zero to sorted list 26 // decrement in-degrees for all nodes they point to 27 // repeat process while the # of in-degree nodes is non-zero 28 // as we work we might also want a parallel list that tracks 29 // the insertion of recipes into our vector to return 30 31 vector<string> canMake = {}; 32 unordered_map<string, Node> graph = {}; 33 34 // len(ingredients[i]) >= 1 so we just push supplies to stack for evaluation. 35 vector<string> stack = {}; 36 for(auto supply: supplies) { 37 graph[supply] = Node(0, supply, false, {}); 38 stack.push_back(supply); 39 } 40 41 // since there can be recipe dependence, we can't do the edge tracking here 42 // basically we might not be able to reference a pre-req here. 43 44 for(auto recipe: recipes) { 45 graph[recipe] = Node(0, recipe, true, {}); 46 } 47 48 for(size_t i = 0; i < recipes.size(); ++i) { 49 Node& recipe = graph[recipes[i]]; 50 recipe.inDegree = ingredients[i].size(); 51 for(auto ingredient: ingredients[i]) { 52 graph[ingredient].requiredBy.push_back(recipes[i]); 53 } 54 } 55 56 while(stack.size() != 0) { 57 58 string current = stack.back(); 59 stack.pop_back(); 60 Node& cn = graph[current]; 61 auto& reqs = cn.requiredBy; 62 63 for(auto rq : reqs) { 64 graph[rq].inDegree -= 1; 65 if(graph[rq].inDegree == 0) { 66 stack.push_back(rq); 67 if(graph[rq].isRecipe) { 68 canMake.push_back(rq); 69 } 70 } 71 } 72 } 73 74 return canMake; 75 } 76 };