从给定原材料中找到所有可以做出的菜
难度:
标签:
题目描述
代码结果
运行时间: 92 ms, 内存: 22.8 MB
/*
* 题目思路:
* 1. 使用Java Stream API实现拓扑排序的逻辑。
* 2. 使用集合保存初始的supplies。
* 3. 通过stream和filter筛选可以制作的菜。
*/
import java.util.*;
import java.util.stream.Collectors;
public class RecipeFinderStream {
public List<String> findAllRecipes(String[] recipes, List<List<String>> ingredients, String[] supplies) {
Set<String> supplySet = new HashSet<>(Arrays.asList(supplies));
Map<String, Long> indegree = new HashMap<>();
Map<String, List<String>> graph = new HashMap<>();
Arrays.stream(recipes).forEach(recipe -> indegree.put(recipe, 0L));
for (int i = 0; i < recipes.length; i++) {
final int index = i;
ingredients.get(i).stream()
.filter(ingredient -> !supplySet.contains(ingredient))
.forEach(ingredient -> {
graph.computeIfAbsent(ingredient, x -> new ArrayList<>()).add(recipes[index]);
indegree.put(recipes[index], indegree.get(recipes[index]) + 1);
});
}
return indegree.keySet().stream()
.filter(recipe -> indegree.get(recipe) == 0)
.flatMap(recipe -> {
Queue<String> queue = new LinkedList<>();
List<String> result = new ArrayList<>();
queue.offer(recipe);
while (!queue.isEmpty()) {
String current = queue.poll();
result.add(current);
if (graph.containsKey(current)) {
graph.get(current).stream()
.filter(next -> indegree.put(next, indegree.get(next) - 1) == 1)
.forEach(queue::offer);
}
}
return result.stream();
})
.collect(Collectors.toList());
}
}
解释
方法:
本题解使用深度优先搜索(DFS)和备忘录技术(lru_cache)来解决制作菜肴的问题。思路包括: 1. 使用图的表示方法,将每个菜肴作为节点,其原材料作为边连接。2. 对于每个菜肴,如果所有原材料都可以通过现有供应或者其他可制作的菜肴获得,则该菜肴可以被制作。 3. 使用DFS和回溯法检查每个菜肴是否可以制作,同时使用三种状态标记节点避免重复计算和检测环。 4. 通过递归深度优先搜索,如果一个菜肴的所有原料都可以获得,则这个菜肴标记为可制作,并添加到供应列表中,以供其他菜肴的原料检查使用。
时间复杂度:
O(m+n)
空间复杂度:
O(m+n)
代码细节讲解
🦆
在构建图的表示中,你是如何处理菜肴之间相互作为原材料的情况?例如,如果菜肴A需要菜肴B作为原材料,而菜肴B反过来需要菜肴A,这种情况下算法如何避免进入无限循环?
▷🦆
题解中提到使用了三种状态标记节点(正在访问,访问完毕,未访问),能否详细解释这三种状态在DFS过程中的具体作用和转换条件?
▷🦆
题解使用了lru_cache来优化DFS的重复计算,具体来说,lru_cache是如何影响DFS的执行效率的?在什么情况下,这种缓存机制会显著提高性能?
▷