当前位置: 首页 > news >正文

Java拓扑排序:2115 从给定原材料中找到所有可以做出的菜

你有 n 道不同菜的信息。给你一个字符串数组 recipes 和一个二维字符串数组 ingredients 。第 i 道菜的名字为 recipes[i] ,如果你有它 所有 的原材料 ingredients[i] ,那么你可以 做出 这道菜。一份食谱也可以是 其它 食谱的原料,也就是说 ingredients[i] 可能包含 recipes 中另一个字符串。

同时给你一个字符串数组 supplies ,它包含你初始时拥有的所有原材料,每一种原材料你都有无限多。

请你返回你可以做出的所有菜。你可以以 任意顺序 返回它们。

注意两道菜在它们的原材料中可能互相包含。

示例 1:

输入:recipes = ["bread"], ingredients = [["yeast","flour"]], supplies = ["yeast","flour","corn"]
输出:["bread"]
解释:
我们可以做出 "bread" ,因为我们有原材料 "yeast" 和 "flour" 。

示例 2:

输入:recipes = ["bread","sandwich"], ingredients = [["yeast","flour"],["bread","meat"]], supplies = ["yeast","flour","meat"]
输出:["bread","sandwich"]
解释:
我们可以做出 "bread" ,因为我们有原材料 "yeast" 和 "flour" 。
我们可以做出 "sandwich" ,因为我们有原材料 "meat" 且可以做出原材料 "bread" 。

示例 3:

输入:recipes = ["bread","sandwich","burger"], ingredients = [["yeast","flour"],["bread","meat"],["sandwich","meat","bread"]], supplies = ["yeast","flour","meat"]
输出:["bread","sandwich","burger"]
解释:
我们可以做出 "bread" ,因为我们有原材料 "yeast" 和 "flour" 。
我们可以做出 "sandwich" ,因为我们有原材料 "meat" 且可以做出原材料 "bread" 。
我们可以做出 "burger" ,因为我们有原材料 "meat" 且可以做出原材料 "bread" 和 "sandwich" 。

示例 4:

输入:recipes = ["bread"], ingredients = [["yeast","flour"]], supplies = ["yeast"]
输出:[]
解释:
我们没法做出任何菜,因为我们只有原材料 "yeast" 。

思路:

将食谱和原料视为图中的节点,原料到食谱的依赖关系视为边,通过广度优先搜索(BFS)遍历图,找出所有可以制作的食谱。

1. Map<String, List<String>> graph

  • 作用:构建图的邻接表,表示 “原料 → 依赖该原料的食谱” 的映射关系。
  • 数据流向
    • 键(Key):原料名称(如 "flour")。
    • 值(Value):依赖该原料的食谱列表(如 ["bread", "cake"])。
  • 构建逻辑:遍历所有食谱的原料,将每个原料对应的食谱添加到列表中。

2. Map<String, Integer> degree

  • 作用:记录每个食谱的入度(即所需原料的数量),用于拓扑排序。
  • 数据流向
    • 键(Key):食谱名称(如 "bread")。
    • 值(Value):该食谱所需的原料数量(如 2 表示需要 2 种原料)。
  • 构建逻辑:遍历所有食谱,统计每种食谱的原料数量。

3. List<String> res

  • 作用:存储最终可以制作的食谱(即所有入度减为 0 的食谱)。
  • 数据流向:在 BFS 过程中,每当一个食谱的所有原料都满足时(入度为 0),将其加入该列表。

4. List<List<String>> ingredients

  • 作用:输入参数,存储每个食谱对应的原料列表
  • 数据流向
    • 外层 List:每个元素对应一个食谱的索引。
    • 内层 List:每个元素是该食谱所需的原料名称(如 ["flour", "water"])。
  • 使用方式:在构建图和入度表时遍历该列表。

5. List<String> graph.get(ingredient)

  • 作用:辅助列表,是 graph 中每个原料对应的食谱列表
  • 数据流向:在 BFS 处理每个原料时,遍历该列表,将对应食谱的入度减 1。

总结

数据结构名称作用
Mapgraph记录 “原料 → 依赖该原料的食谱” 的映射,用于构建图。
Mapdegree记录每个食谱的入度(所需原料数量),用于拓扑排序。
Listres存储最终可制作的食谱。
Listingredients输入参数,存储每个食谱的原料列表。
Listgraph.values()辅助列表,存储每个原料对应的食谱列表(用于 BFS 遍历)。
public class Solution {// 主方法:寻找所有可以制作的食谱public List<String> findAllRecipes(String[] recipes, List<List<String>> ingredients, String[] supplies) {// 构建图结构:记录每个原料可以用来制作哪些食谱Map<String, List<String>> graph = new HashMap<>();// 记录每个食谱所需的原料数量(入度)Map<String, Integer> degree = new HashMap<>();// 遍历所有食谱,构建图和入度表for (int i = 0; i < recipes.length; i++) {String recipe = recipes[i];List<String> ingredientList = ingredients.get(i);// 对于每个食谱的每种原料for (String ingredient : ingredientList) {// 如果该原料还没有在图中,为其创建一个列表graph.putIfAbsent(ingredient, new ArrayList<>());// 将当前食谱添加到该原料可以制作的食谱列表中graph.get(ingredient).add(recipe);}// 记录该食谱所需的原料数量(即入度)degree.put(recipe, ingredientList.size());}// 存储最终可以制作的食谱List<String> res = new ArrayList<>();// 使用队列进行广度优先搜索,初始时将所有可用的补给加入队列Queue<String> queue = new LinkedList<>(Arrays.asList(supplies));// BFS遍历:处理所有可用的补给和可制作的食谱while (!queue.isEmpty()) {String supply = queue.poll();// 如果当前补给可以用来制作某些食谱if (graph.containsKey(supply)) {// 遍历该补给可以制作的所有食谱for (String recipe : graph.get(supply)) {// 减少该食谱所需的原料数量(入度减1)degree.put(recipe, degree.get(recipe) - 1);// 如果该食谱所需的所有原料都已满足(入度为0)if (degree.get(recipe) == 0) {// 将该食谱加入队列,以便后续检查它是否可以作为其他食谱的原料queue.offer(recipe);// 将该食谱加入结果列表res.add(recipe);}}}}return res;}
}

另一种更简单直观的方法:

class Solution {public List<String> findAllRecipes(String[] recipes, List<List<String>> ingredients, String[] supplies) {// 存储最终可以制作出来的食谱列表List<String> res = new ArrayList<>();// 使用队列来处理当前可用的原料(包括初始补给和新制作出的食谱)Queue<String> q = new LinkedList<>();// 将所有初始补给加入队列for (int i = 0; i < supplies.length; i++) {q.offer(supplies[i]);}// 当队列不为空时,持续处理可用的原料while (!q.isEmpty()) {// 取出当前可用的原料String supplie = q.poll();// 遍历所有食谱的原料列表for (int i = 0; i < ingredients.size(); i++) {// 获取当前食谱的原料列表List<String> list = ingredients.get(i);// 如果原料列表为空,跳过当前循环(实际题目中应该不会出现这种情况)if (list.size() == 0) {continue;}// 从原料列表中移除当前可用的原料// 注意:这里直接修改了原始输入的ingredients列表list.remove(supplie);// 如果移除后原料列表为空,说明该食谱所需的所有原料都已满足if (list.size() == 0) {// 将该食谱添加到结果列表中res.add(recipes[i]);// 同时将该食谱作为新的"原料"加入队列,以便后续检查依赖它的食谱q.offer(recipes[i]);}}}// 返回最终可以制作的食谱列表return res;}
}

 

http://www.dtcms.com/a/289486.html

相关文章:

  • Linux 基本指令详解
  • Self-Consistency:跨学科一致性的理论与AI推理的可靠性基石
  • WebDriver 对象中的方法
  • C++STL系列之list
  • Vue DIY 内容文本超出组件
  • Numpy库,矩阵形状与维度操作
  • 矩阵算法题
  • ZYNQ创新实践:免IIC驱动直控MCP4661T数字电位器
  • ollama基本配置
  • 仙盟数据库应用-外贸标签打印系统 前端数据库-V8--毕业论文-—-—仙盟创梦IDE
  • 数据库操作丨C++ 操作 数据库——SQLServer 篇
  • 数据库技术总结
  • 激光雷达和相机在线标定
  • 试用SAP BTP 06:AI服务-Data Attribute Recommendation
  • Java行为型模式---解释器模式
  • 30天打牢数模基础-XgBoost讲解
  • 第四章第一节 OLED 调试工具
  • 【LeetCode 热题 100】200. 岛屿数量——DFS
  • 20250720-3-Kubernetes 调度-资源限制对Pod调度的影响(2)_笔记
  • 隧道无线调频广播与“群载波”全频插播技术在张石高速黑石岭隧道中的应用
  • 数据结构第二章:线性表之顺序表
  • Kubernetes (K8S)知识详解
  • 【k8s集群管理平台】k8s运维管理的新玩法,让运维电脑随时不离身的现状成为过去
  • 【论文研读】SlowFast Networks for Video Recognition
  • 2024年全国青少年信息素养大赛Scratch算法创意实践挑战赛 小高组 初赛 真题
  • http基础一
  • HarmonyOS 启动提速秘籍:懒加载全链路实战解析
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘lxml’问题
  • 红宝书单词学习笔记 list 51-75
  • 基于Chinese-LLaMA-Alpaca-3的多模态中医舌诊辅助诊断系统设计与实现