华为OD机试 2024D卷题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试(JAVA)真题(D卷+C卷+A卷+B卷)》。
刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。
一、题目描述
一个应用启动时,会有多个初始化任务需要执行,并且任务之间有依赖关系,例如A任务依赖B任务,那么必须在B任务执行完成之后,才能开始执行A任务。
现在给出多条任务依赖关系的规则,请输入任务的顺序执行序列,规则采用贪婪策略,即一个任务如果没有依赖的任务,则立刻开始执行,如果同时有多个任务要执行,则根据任务名称字母顺序排序。
例如:B任务依赖A任务,C任务依赖A任务,D任务依赖B任务和C任务,同时,D任务还依赖E任务。那么执行任务的顺序由先到后是:A任务,E任务,B任务,C任务,D任务。这里A和E任务都是没有依赖的,立即执行。
二、输入描述
输入参数每个元素都表示任意两个任务之间的依赖关系,输入参数中符号->表示依赖方向,例A->B表示A依赖B,多个依赖之间用单个空格分割。
三、输出描述
输出为排序后的启动任务列表,多个任务之间用单个空格分割。
1、输入
A->B C->B
2、输出
B A C
3、说明
任务A和C都依赖于任务B。任务B执行后,A和C立即执行,A和C的执行顺序按照字典序排列。
四、解题思路
这道题目涉及有向无环图(DAG)的拓扑排序问题。我们需要按照任务的依赖关系顺序来安排任务的执行,确保每个任务在其依赖任务之后执行。如果同时有多个任务可以执行,则按照任务名称的字母顺序进行排列。以下是具体的解题思路:
- 解析输入:
- 将输入的依赖关系字符串解析成任务之间的依赖关系对。
- 构建依赖图和入度表:
- 使用两个哈希表来表示任务的依赖关系图和每个任务的入度(被依赖的次数)。
- 依赖关系图使用 Map<String, List>,记录每个任务的后续任务。
- 入度表使用 Map<String, Integer>,记录每个任务的入度值。
- 初始化准备队列:
- 使用一个列表 readyTasks 来存储所有入度为0的任务(即没有任何依赖任务,可以直接执行)。
- 遍历入度表,将所有入度为0的任务加入准备队列。
- 拓扑排序:
- 使用 StringJoiner 构建任务的最终执行顺序。
- 通过一个 while 循环处理准备队列中的任务:
- 按字母顺序对当前准备执行的任务进行排序。
- 依次处理每个准备好的任务,将其添加到执行顺序中。
- 遍历当前任务的所有后续任务,更新它们的入度值。如果某个后续任务的入度变为0,则将其加入下一轮的准备队列。
- 将当前轮的准备队列更新为下一轮的准备队列,继续处理。
- 输出结果:
- 输出最终的任务执行顺序,确保任务按依赖关系和字母顺序正确排列。
五、Java算法源码
public class Test01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取输入的依赖关系,并分割成二维数组
String[][] dependencies = Arrays.stream(scanner.nextLine().split(" "))
.map(s -> s.split("->"))
.toArray(String[][]::new);
// 用于记录每个任务的入度(有多少任务依赖它)
Map<String, Integer> taskInDegree = new HashMap<>();
// 用于记录每个任务的依赖关系图
Map<String, List<String>> taskGraph = new HashMap<>();
// 构建图和入度表
for (String[] dependency : dependencies) {
String dependentTask = dependency[0]; // 依赖任务
String prerequisiteTask = dependency[1]; // 前置任务
// 初始化前置任务的入度为0
taskInDegree.put(prerequisiteTask, taskInDegree.getOrDefault(prerequisiteTask, 0));
// 增加依赖任务的入度
taskInDegree.put(dependentTask, taskInDegree.getOrDefault(dependentTask, 0) + 1);
// 构建依赖关系图
taskGraph.putIfAbsent(prerequisiteTask, new ArrayList<>());
taskGraph.get(prerequisiteTask).add(dependentTask);
taskGraph.putIfAbsent(dependentTask, new ArrayList<>());
}
// 用于存储所有入度为0的任务(没有依赖的任务)
List<String> readyTasks = new ArrayList<>();
for (String task : taskInDegree.keySet()) {
if (taskInDegree.get(task) == 0) {
readyTasks.add(task);
}
}
// 用于构建最终的任务执行顺序
StringJoiner executionOrder = new StringJoiner(" ");
// 处理所有准备好的任务
while (!readyTasks.isEmpty()) {
// 如果同时有多个任务要执行,则根据任务名称字母顺序排序
readyTasks.sort(String::compareTo);
// 用于存储下一轮入度为0的任务
List<String> nextReadyTasks = new ArrayList<>();
// 处理当前轮所有的准备好执行的任务
for (String currentTask : readyTasks) {
executionOrder.add(currentTask); // 将任务添加到执行顺序中
// 遍历当前任务的所有后继任务
for (String nextTask : taskGraph.get(currentTask)) {
taskInDegree.put(nextTask, taskInDegree.get(nextTask) - 1); // 将后继任务的入度减1
// 如果后继任务的入度变为0,则将其加入下一轮的准备队列
if (taskInDegree.get(nextTask) == 0) {
nextReadyTasks.add(nextTask);
}
}
}
// 准备处理下一轮的任务
readyTasks = nextReadyTasks;
}
// 输出最终的任务执行顺序
System.out.println(executionOrder);
scanner.close(); // 关闭扫描器
}
}
六、效果展示
1、输入
B->A C->A D->B D->C D->E
2、输出
A E B C D
3、说明
🏆下一篇:华为OD机试 - 简易内存池 - 逻辑分析(Java 2024 C卷 200分)
🏆本文收录于,华为OD机试(JAVA)真题(D卷+C卷+A卷+B卷)
刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。